CSC/ECE 517 Fall 2007/wiki3 6 ub: Difference between revisions
Line 134: | Line 134: | ||
'''ProductCatalogHandler''' | '''ProductCatalogHandler''' | ||
Get Categories | Get Categories | ||
Get Product in Category X | Get Product in Category X | ||
'''ShoppingCartHandler''' | '''ShoppingCartHandler''' | ||
Get Items in Shopping Cart | Get Items in Shopping Cart | ||
Add Item to Shopping Cart | Add Item to Shopping Cart | ||
Revision as of 03:19, 20 November 2007
Take the Controller pattern (which we did not cover in class) and catalog the information on it available on the Web. Find good descriptions and good, concise, understandable examples. Tell which you consider the best to present to a class.
What are Design Patterns
Patterns are simply proven solutions to common problems. A pattern addresses a recurring design problem that arises in specific design situations and presents a solution to it. This is done by defining a set of rules which describes how to solve the problem at hand.
It is often the case that patterns are not invented but are discovered. Sometimes a pattern can be as simple as an advice from a previous designer, which helps future designers to cope with new situations.
A design pattern by no means is a panacea. It is not as easy as finding the right pattern and simply applying it to get the solution. The application of a pattern to a problem requires careful analysis to ensure that the pattern actually applies to the problem. It is important to make sure the pattern does not have negative side effects upon the rest of the system or other requirements.
Characteristics of Good patterns
• It solves a problem
• It is a proven concept
• The solution isn't obvious
• It describes a relationship
• The pattern has a significant human component
GRASP Patterns
These belong to a type known as process patterns. They describe an appropriate way of performing tasks. GRASP stands for General Responsibility Assignment Software Patterns.
General => Abstract; widely applicable
Responsibility => Obligations, duties
Assignment => Giving a responsibility to a module
Software => Computer code
Patterns => Regularities, templates, abstractions
There are several GRASP patterns, but we will only look at a few of the more important ones. Some of them are simply good design principles, and one can argue whether they are really patterns. For example, High Cohesion and Low Coupling are two that are well-known design principles and not really patterns.
The full set of GRASP patterns are:
1. Information Expert
2. Creator
3. Controller
4. Low Coupling
5. High Cohesion
6. Polymorphism
7. Pure Fabrication
8. Indirection
9. Protected Variations
GRASP can be used as a methodical approach to learning basic object design. These are patterns of assigning responsibilities. There are two types of responsibilities:
- Knowing responsibilities that include knowing about private encapsulated data, about related objects, and things it can derive or calculate.
- Doing responsibilities include doing something itself, like creating another object or doing a calculation, initiating action in other objects, and controlling and coordinating activities in other objects.
Controller Pattern
The Controller pattern addresses the question: Who handles a system event?
The events under consideration here are the ones initiated from a source outside the system. Thus the system should have some class that receives the event, but that does not necessarily mean that it should handle the event.
For example security video cameras are meant to receive an event wherein there is an attempt to intrude into a house but they do not take any steps to catch the intruder. Thus they are mere receivers and the event handling is done by some other part of the security system.
So the controller pattern can be used when we are faced with the problem of assigning responsibility of handling a system event. The solution to this problem as proposed by the controller patterns is as follows:
If a program receives events from external sources other than its graphical interface, add an event class to decouple the event source(s) from the objects that actually handle the events.
The events should be handled by classes representing one of the following choices:
- A class that represents the overall system, device, or subsystem (facade controller).
- A class that represents a use case scenario within which the system event occurs. These are often named <usecasename>Handler, <usecasename>Controller,<usecasename> Manager, and so forth.
Whether to use façade controller or use case controller?
Facade Controller
If we do not have a lot of messages that need to be handled by the controller, we can use a single object that represents the overall system. For example, if we are building an application that manages our contacts, addresses, and phone numbers, you could call this object “AddressBook.” If we are building an e-commerce website, we could call this object “Store.” If we are building a chess game, we could call this object “ChessGame.“
Use Case or Session Controller
On the other hand, if we have a lot of messages that needed to be handled by the controller, we risk the chance of losing cohesiveness if we use a single facade controller. In this case, we should define a single controller for all the system events associated with a single use case. So, in our e-commerce website example above, we may have several use case controllers, called “HandleReturn”, “ProcessSale”, “ProcessPayment”, “ManageAccount”, etc. Thus for most applications, the use case or session controller tends to be used.
Advantages of Controller Pattern
- There is increased potential for reuse. Using a controller object keeps external event sources and internal event handlers independent of each other’s type and behaviour.
- It provides more information about the states of the use case. It also enables us to ensure that the system operations occur in a legal sequence by providing more information about the current state of activity and operations within the use case.
Examples
Example 1
In this example a use case controller is used.This is because there are a lot of unrelated messages coming from the UI and and it doesn't make sense for a single facade controller to manage all requests.For example, in the case of an e-commerce application, we will have the following messages:
1. Get Categories
2. Get Product in Category X
3. Get Items in Shopping Cart
4. Add Item to Shopping Cart
In this case the first 2 messages that are related to a ProductCatalog can be assigned to a ProductCatalogHandler and the last 2 messages that are related to the shopper's cart can be assigned to a ShoppingCartHandler.
ProductCatalogHandler
Get Categories
Get Product in Category X
ShoppingCartHandler
Get Items in Shopping Cart
Add Item to Shopping Cart
This keeps the ProductCatalogHandler and ShoppingCartHandler highly cohesive.
Example 2
Consider an example of a convenience store where a cashier can trigger three events namely
enterItem() - Used to enter the item purchased by the customer.
endSale() - Marks the end of the sale and proceeds towards payment.
makePayment() - Initiates payment by the customer.
The problem can be stated as: Who has the responsibility for the enterItem() event? By the controller pattern we have four solutions to our problem
1. It can either be the overall system indicated by POST
2. It can be the overall business indicated by STORE
3. It can be someone in the real world who is active in the task namely the cashier
4. It can be an artificial handler of all system events of a use case denoted by BuyItemsHandler().
The choice of which one to use will be influenced by other factors such as cohesion and coupling.
A good design by the controller pattern is shown as follows
It is important to note how the presentation layer is decoupled from the domain layer.
Assigning the responsibility for system operations to objects in the domain layer rather than presentation layer supports increased reuse potential. It also makes it easier to unplug the interface layer and use a different interface technology, or to run the system in an off-line “batch” mode.
Example 3
A game of monopoly is a good example of a controller pattern in which the actors are the players who generate events like clicking a button with a mouse to play a game or make a move. The UI software objects (such as a JFrame window and a JButton) must process the event and cause the game to play. When objects in the UI layer pick up an event, they must delegate the request to an object in the domain layer.
The problem in this case can be formulated as follows:
What first object beyond the UI layer should receive the message from the UI layer?
As per the controller pattern the solution is as follows:
Assign the responsibility to an object representing either of following:
- Represents the overall “system” – a root object
- Represents a use case scenario within which the system operation occurs.
Here again there is clear separation between the UI layer and the domain layer.
Example 4
In an example of Jukebox program, responsibility is assigned to a controller class to handle events from external actors, e.g. startup(), playSongs(), etc. The controller class represents the overall system, device, or subsystem, which often don’t do the work, but delegate it to processing layer. Processing layer is responsible for actually doing work by calling methods such as deviceInitialize() and executePlaySongs().
References
3. Detailed description of GRASP patterns
External Links
4. Wikipedia entry on GRASP patterns