Cantara Client architecture is defined in terms of logical, process, development and deployment perspectives.
The main logical components of the Cantara Client architecture are the View, Interactor and Presenter (VIP).
Strict boundaries exist between these components; they can only pass each other request, response and view models. The flow of execution moves always in one direction, as shown below.
Flow of Execution
The following sections provide information about how this model is used.
Extending the Model
In CC6, the VIP model is extended to include additional components:
Together, these components form the basis of a CC6 Scene.
Scene Design Objectives
A Scene consists of a specific set of protocols that conform to the VIP model.
- In CC6 development, a Protocol is the same as an Interface.
- Protocol is an iOS term, and Interface is an Android term.
The objective of the design is to avoid the "Massive View Controller" syndrome. By separating logic where possible, the complexity of a CC6 Scene is reduced. Each protocol in a Scene is designed to handle only a single responsibility. When business rules necessitate changes to the underlying data models, there is no impact on the Scene.
Passing data between the VIP components (View→ Interactor→ Presenter→View) is done through entities consisting of primitive types. Structs, classes, enums or protocols can be used represent the data, but there should only be primitive types inside these entities.
Each Component is designed in a way that it can be plugged into its relevant part of a Scene. This allows a developer to swap out a default component with a custom one, as long as it conforms to the defined protocols.
The extended model shown above represents only a single View, however a Scene can potentially contain many Views.
Each View can be further decomposed into Fragments. Fragments correspond to specific areas of screen real-estate, and a particular Fragment may not always be visible at any point in time. The exact number of Fragments required by a View will depend on the View's complexity, and whether it is being displayed on a tablet device or a phone.
The fragment layout example pictured below is for the View Purchase Orders screen. The class diagrams which follow show how the Fragments are managed. Note that the classes used to implement the components of the Scene model are slightly different on iOS and Android.
Each of the classes shown In the above sequence diagram is a protocol. How each protocol is implemented is up to the developer - e.g. on Android, the Fragment Manager and Presenter functionality are actually part of the Activity class, but on iOS they are implemented with separate classes.
The table below summarises the responsibilities of each of the components supporting a Scene.
The Interactor contains the business logic. This is where decisions are made about where / how to store data, and make changes to the application state. These actions are performed by Workers attached to the Interactor.
An Interactor is generally attached to a Scene, but can persist beyond the Scene's lifecycle. For example, when an Android screen is being rotated by the user, the Scene gets destroyed and recreated. However, the Interactor has been designed to persist, in order to avoid losing operations or data during the screen rotation.
Actions are performed by one or more Workers attached to the Interactor. The number of Workers is dependant on the business logic required for the Scene. To manage these actions, the Interactor exchanges request objects with its Workers.
The tasks performed by a Worker are completed by a background thread in 99% of cases. Workers are designed to be reusable by multiple Interactors.
Workers should be:
A View is responsible for rendering a presentable state of the application to the user.
|The Presenter is responsible for translating business models into view model objects. In some cases this translation is minor and does not warrant a separate Presenter class, in which case the Presenter can be in the View.
The Router is responsible for separation of navigation logic from the View. The Router creates new Scenes and injects the relevant data into the new Scenes through the Interactor's data store.
(not required for Android)
The Fragmenter is responsible for attaching, detaching and laying out fragments.
Interactors and Resources
Each scene is supported by its own derived Interactor class. The Scene interacts with one or more Resources to access databases and networked services. These operations make use of the Dao and Service classes.
The example below shows the Interactors and associated Resources for two Scenes:
- View Orders Awaiting Approval
- Approve / Reject Purchase Order.
In this example, the Resources supporting the Interactors are shared between the Scenes. Note that the View and Presenter have been omitted for clarity.
Scene and Resource Interactions
Workers are a tool that can be used in many parts of the architecture. They inherit from an API protocol defining how to interact with that particular Worker.
The Worker in the PurchaseOrderHeader Resource shown above is responsible for coordinating database and network transactions, performed with the Dao and Service objects.
When these transactions are complete, the Interactor is informed of the result. The Resource process flow is shown below.
Resource Process Flow
Views and Fragments
Whilst the architecture model's View is implemented slightly different on iOS and Android, both platforms use Fragments to provide the various parts of a Scene.
- On iOS, a ViewController interacts with a Fragmenter class to create, attach and manage fragments. A fragment must have a ViewModel.
- On Android, fragments are attached to an Activity via a View, and the OS then manages those fragments.
- On both platforms, individual fragments are responsible for raising user input events that must be handled by a Responder.
The diagram below shows the iOS and Android implementations of the ViewPurchaseOrders Scene. In this Scene, the ViewController actually takes on the responsibility of implementing the Responder, rather than delegating to a separate class.
iOS and Android Implementations of ViewPurchaseOrders Scene
Handling User Input
The Scene input handling process is described below, using the example of the Approve Order use case:
- The user will interact with the View through an 'Approve' button.
- The View constructs a request object and sends it to the Interactor.
- The Interactor takes the request object and delegates the work to a Worker.
- The Worker coordinates action between a Store and API to ultimately approve the order in JDE and update the local store.
- A result is handed back to the Worker and the Interactor.
- The Interactor takes the result and puts it into a response object which is passed to the Presenter.
- The Presenter takes the response and formats the result into a view model object which it sends to the View.
- The View displays the view model, showing that the order is approved.
- A Scene's Presenter may be part of the ViewController/Activity, or it may have its own separate class.
- For simple model transformations, a Presenter may not be required.
- A Scene must be able to work without a Presenter