In this part of article for "Software patterns- GRASP", we would run through the process of assigning responsibilties of coordinating or controlling the system/ UI events.
Objective
To understand the GRASP pattern “Controller”
Preface
We have explored what are patterns and GRASP (in part I), Information Expert in part II and Creator in part II. In this part IV, we would focus on next GRASP pattern named “Controller”. The principle behind this pattern is “Who should be responsible for handling a system event?” or “Who should be responsible for UI events” or “ Who handles events from external actors (UI included), e.g. startup() etc?”
Problem: Who should be responsible for handling a system event?
Solution: Assign the responsibility for handling a system event message to a class representing one of the following
· A class that represents the overall system, device, or sub-system(facade controller) e.g. Jukebox.
· A class that represents a use case within which the system event occurs (a session controller or use case controller) Example: makeSaleHandler, makeSaleCoordinator, etc.
· Represents the overall business (facade controller)
· Represents something in real world that is active (role controller)
These classes often don’t do the work themselves, but delegate it to others and in other terms it coordinates or controls the activity.
The decision to create the specific controller i.e. system controllers vs. use case controllers are often driven and influenced by the dynamics of high cohesion vs. low coupling scenario.
Approach:
Step I: Closely look at domain/ design model and when you have family of classes doing work/job pertaining to some specific function and would need some facilitator
e.g. if one has requirement to connect to multiple databases and has the DAL, a CommunicationManager class can be introduced to control and manage DAL and connection to different database
Step II: Add a new class to take the responsibility of controller or manager and all client code would access the functionality through this class
Description
Let’s extend an example of POS (Point Of Sale) systems explained in previous part. In the domain model, following classes are identified. These classes are shown in the left part of diagram (Fig. No.1). There are many system operations such as closing a sale, make payment etc which are related to business function “Sales”.
Controller pattern gives following choices
· represents overall system
· represents the overall business
· MakeSaleHandler- an artificial handler of all system operations
Following diagram depicts the Controller pattern. Compared to Creator pattern, it has additional class called makeSaleHandler (in fact the “Register” class shown in the article for Creator pattern can be called as controller) which controls and coordinates the sale.
Cashier - represents some role in real-world that is active in the task
UI Form- shows the UI layer for POS software system
Class |
Relationship with other classes |
Responsibility and method |
MakeSaleHandler |
Controls the“Sale” |
Controls and coordinates the sale through makeSaleLineItem() |
Sale
|
Composite aggregation with SaleLineItem |
Creating an instance
makeSaleLineItem() |
This is an example of a use case handler which would be used to deal with all system events of a use case, and may be used for more than one use case (e.g. for use cases “Create User” and “Delete User”, one can have one UserController, instead of two separate controllers). In this case the use case is “Create SaleLineItem”
If you choose use case controller,, you might want to use the some controller class for all system in a particular use case scenario. E.g. for POS system one can have POSController through which all system events would be routed to domain (as well as business logic) layer. In some scenarios, the only reason for not doing so is that the class can become too complex and it becomes better to delegate the work.
Controller is defined as the first object beyond the UI layer that receives and coordinates ("controls") a system operation (triggered by user of the system). The controller should delegate to other objects the work that needs to be done; it should not do much work itself. The GRASP Controller can be thought of as being a part of the Application/Service layer (assuming that the application has made an explicit distinction between the Application/Service layer and the Domain layer) in object-oriented systems with layered pattern implemented.
What such controller does?
· It sees to it that the messages are sent to the correct expert in the model. (e.g. “Sale” class)
· The reason to have a controller is to separate the business model called domain objects from the visual logic called view objects
Once the decision to have a controller is decided, the real question is choosing which concept is to be the controller class
· This is relatively easy as the concept that processes the system events is the logical choice
· In the above case, cashier is really an actor the runs the posting of sale. Hence it can’t be a controller.
The classes which represent the overall system, sub-system or devices are called as Facade controllers and it is suitable when there are few events.
When Use-case controllers are used, there will be one controller for each use-case.
Bloated Controller: There are the controllers which handle too many system events leading to low cohesion. This would happen when only one class is receiving all system events. These perform many of the tasks for handling events without delegating the work and also has significant amount of information which should have distributed to other project. Sometimes it duplicates information found somewhere else. Such controller better be avoided and they can be avoided by addition of few more controllers.
Design the controller in such a way that it primarily delegates the fulfillment of each system operation to other objects.
Related Patterns: This patterns needs to be studied from the angle of understanding and applying principle. The patterns related to this are “Low Coupling” and “High Cohesion”.
Benefits:
· Supports Low Coupling
· Promotes Understandability, maintainability
Liabilities /Contradictions:
· Sometimes grouping of responsibilities or code into one class or component to simplify maintenance occurs when controllers are designed. This should be avoided as it would become bloated controllers as discussed above.
Summary and Conclusion
In this part, we discussed what Controller is and also the principle behind this. We discussed the steps for assigning responsibility. We saw practical example from POS (Point Of Sales) and explanation for having a controller. Specifically we saw an example of use case controller. The benefits and contradiction are mentioned with reference to availability of other patterns too. The actual implementation of such principles is Page Controller, FrontController in APS.NET, and then the generic MVC (GoF pattern) is also an example of applying this principle.
To reiterate, following patterns for design would result into highly maintainable, robust and reusable systems.
Happy Designing!!!
Additional Reading
Front Controller: http://msdn.microsoft.com/en-us/library/ff648617.aspx
MVC: http://martinfowler.com/eaaDev/uiArchs.html