Application Design

Patterns used

Object-Oriented Programming

ConKUeror is being developed with the object-oriented programming (OOP) principles in mind. This means that the code is organized into objects that represent the game's entities, such as the game map, the game deck, and the player objects. OOP is also aligned with our “Modularity” principle, which means that the code is easier to read, maintain, and extend.

Some common OOP patterns used in the development of ConKUeror include inheritance and polymorphism. Inheritance is used to create subclasses of the army objects, such as the Infantry, Cavalry, and Artillery objects. Polymorphism is used to allow the game to handle different types of objects in a consistent way, such as when determining the outcome of an attack. Use of OOP principles allows for a more organized and efficient development process, resulting in a better game for the end user.

Application Startup

Builder

The AppController and Router classes use the Builder Pattern to construct the ConKUeror application in steps, as shown in the diagrammatic representation of the ConKUeror startup. This allows for efficient and flexible construction of complex objects, which enhances the application's performance and responsiveness.

See:

Creator

The Router class in ConKUeror uses the Creator pattern to create and cache ViewPanel and ViewController objects. The Router reads the annotations on each ViewPanel and ViewController to determine their associated route, and uses the initialize() method on each object to instantiate it. Once the object is created, the Router adds it to a cache for later use.

This approach allows for dynamic creation and caching of ViewPanel and ViewController objects, which can be useful in situations where large numbers of objects need to be created and managed. By using the initialize() method to create the objects, the Router can ensure that each object is properly configured before it is used, and by caching the objects, the Router can reduce the overhead associated with creating new objects.

The use of annotations to associate each ViewPanel and ViewController with specific routes also provides a convenient and flexible way to manage application navigation, as it allows developers to easily add, remove, or modify navigation routes without having to modify the individual codes.

Multithreading

In ConKUeror, the loading of necessary resources and initialization tasks are performed using the Swing Worker Thread, by invoking the preload() method of each ViewController, which allows the loading process to happen in the background while the user sees the loading screen. This ensures that the main thread is not blocked and that the application remains responsive. The Swing Worker Thread also provides a built-in mechanism for canceling the loading process and handling errors. By using the Swing Worker Thread, ConKUeror is able to provide a fast and responsive interface while still ensuring that important resources are loaded before the main screen appears.

See:

UI Rendering

Model-View Separation

In ConKUeror, model-view separation is achieved by separating the model, user interface, application code, and controller classes into different packages. The model is located in the domain package, while the user interface, application code, and controller classes are located in the ui package. This separation allows for a clear separation of concerns and makes it easier to maintain and modify the code.

Controller

In ConKUeror, the ViewController pattern is used to handle communication between the domain and the UI. ViewController classes are responsible for handling user input and updating the UI accordingly. ViewPanels are responsible for rendering the Swing components, and have their respective ViewController as a type parameter. For example, MainView extends ViewPanel<MainController>. This allows for easy access to the controller's methods throughout the view panel, by calling the getController() method. This approach follows the Facade pattern, which simplifies the interface to a complex system by providing a unified interface to a set of interfaces in a subsystem.

Multithreading

Multithreading is also used in ConKUeror to handle animations and other time-sensitive operations, ensuring that the UI remains responsive and fluid even during complex or resource-intensive tasks.

Application Navigation

Facade

In ConKUeror, the custom router class, Router, for navigating and constructing view panels and view controllers uses the Facade pattern implemented in the ViewController class. This class implements the RouterRedirect interface, which defines the redirect(Route route) method for navigation. By encapsulating the logic for constructing the view panel and view controller for the target view using the Facade pattern, the router provides a simplified interface for navigation while reducing coupling and hiding irrelevant implementation details from UI code.

The facade pattern is also used to simplify the interface of the ViewPanel and ViewController lifecycle hooks. These hooks are implemented as separate methods with specific names, such as preload(), initialize(), onRoute(), onMount(), and onUpdate(). However, they are all activated on the chain of responsibility by the same facade method, redirect(), which is used for navigation.

When the application is loading, it first calls the preload() method, which is used to load any necessary data or resources before the view is initialized. Then, it calls the initialize() method, which is used to set up the initial state of the view and controller. Finally, it calls the onRoute(), onMount(), and onUpdate() methods as needed, depending on the specific lifecycle of the view.

By using the facade pattern, ConKUeror is able to provide a simple and consistent interface for managing the lifecycle of its views and controllers, while still allowing for a high degree of flexibility and customization. This makes it easy to add new views and controllers to the application, and to modify or extend the behavior of existing ones.

See:

Diagrammatic representation of the application startup process.

Diagrammatic representation of the application startup process.

Class diagram for the Router and its relation to the navigation system.

Class diagram for the Router and its relation to the navigation system.

Global Application Context

Global Application Context

Decorator

In ConKUeror, the decorator pattern is implemented using annotations. ViewPanels and ViewControllers are annotated with @View and @Controller, respectively, and provided with the specific route they handle, for example, @Controller(at = Route.Main). This enables the separation of concerns between different parts of the application navigation, while still allowing for the addition of behavior to individual objects in a flexible and dynamic way.

See:

Chain of Responsibility

In ConKUeror, the router class uses the redirect(Route route, Object... args) method to navigate between views by propagating the route through a chain of responsibility. The method takes a Route object and an optional list of arguments, which can be used for passing data between views.

By using the chain of responsibility pattern, the router class provides a flexible and extensible system for navigation between views. New ViewController objects can be added or removed easily without affecting the existing ones, and different ViewController objects can be used for different types of events.

The chain of responsibility design pattern can be particularly useful for handling UI updating and rerendering in ConKUeror. When an update is triggered from anywhere in the application, including the global application Context object (a singleton), the update signal is handled on the chain of responsibility and delegated to all the necessary application objects, such as views and controllers. This ensures that the update is propagated throughout the application in an efficient and organized manner.

See:

Route lifecycle. Left: Application Startup. Center: Application Navigation. Right: View Updates

Route lifecycle. Left: Application Startup. Center: Application Navigation. Right: View Updates

Strategy

In ConKUeror, the strategy pattern is implemented using the view and controller hooks. Views and controllers are the two fundamental components of the ConKUeror application design that handle the communication between the domain and the UI. The hooks are used to define the different stages in the lifecycle of a view or controller.

Hooks are triggered in three events: Startup, Navigation, Update.

Views have four hooks: