These patterns are more specifically concerned with communication between objects.
Here are Chain of Responsibility Pattern, Iterator Pattern, Command Pattern and Mediator Pattern.
Chain of Responsibility
It allows a number of classes to attempt to handle a request, without any of them knowing about the existence or capabilities of other classes. So a lose coupling occurs between these classes and the request object passed to these classes is the only common link.
The request is passed through these classes until any one of these handles this request. Generally once handled, no other classes are visited. But a distorted form of this pattern allows more than one class to handle the request and process it, like servlets filters.
Example
- A help system, which can take the request for help from specific portion of UI. A chain of different help handlers in help system can try to handle this request and if any handler is successful to handle this request, it will do the processing. Further no handler will be invoked by core system.
- We have the requirement to process some of the data from flat files and based on this data and some other parameters to the system, have to feed this data to database. The processing flow may vary depending on type of data and supplied parameters. Here distorted form of chain of responsibility can be applied.
Usage
- It reduces the coupling among objects. Objects need not to be familiar with each other, they just should be able t o forward the request to next request handler.
- It helps us in structured programming i.e. we can divide the responsibilities among the objects.
- The request handlers can be added or removed dynamically based on some xml or flat configuration file.
When to Use
- When processing logic for request may vary depending on request attributes or other parameters.
- When more than one objects qualify to handle t he request.
- When we want to add or remove the request handler objects dynamically i.e. want to make these highly configurable using configuration files.
- When sequence of objects, handling the request, may need to change for different kind of requests.
Drawbacks
- The request handlers must be implemented by an interface (especially if there are already extended from any other class). Here duplicate code will exists with the handlers to get the next handler and forward the request to it.
Command Pattern
The system chooses the right request handler for a request and forwards the request to it. Unlike chain of responsibility, where the request used to forward to multiple handlers and any qualified handler can handle it, here system finds the qualified request handler and hand over the request to it.
Point to consider is that all the request handlers i.e. command objects must be implemented by a common interface so that the system can choose and command without knowing its actual implementation and request it for processing the menu action.
Example
- A UI has a menu with different menu items which can serve different purposes. One way to define t he action for menu items to define a request handler class and put the logic for all the items in this using if – else construct. But this could be a very crude, non-extensible and non-maintainable solution. Other solution is to define different request handlers for each menu item and choose the right one before asking for processing using Command Pattern.
- If we need to implement Undo functionality, command pattern is the best strategy. A separate object can be created with all the information required to undo-redo the actions and can be put to the stack. Here objects are not known to each other and also not dependent on anyone, but are capable to do their own action based on the given command.
Usage
- Helps us to define a structured system where every command object has code only for one action event.
- New request handlers i.e. commands can be added easily to the system.
- Client application is not dependent on the implementation of various actions, thus any change can be done easily.
When to Use
- When we have a number of different requests.
- When we want to abstract the implementation of different UI actions from UI.
- When extensibility is the requirement.
Iterator Pattern
It is used to iterate over a collection of elements, without knowing what is contained in the list. It is the most simple pattern and used heavily.
A slight different implementation can have a filter with it which can be used to filter out the desired elements from the collection.
Example
- In java, we can ask the collection for iterator and can traverse the whole list using it.
Usage
- Simple and convenient way to iterate over a collection of elements, or filtered elements depending on the requirement and implementation of iterator.
When to Use
- When requirement is to iterate over a collection of elements
Drawbacks
- Underlying data of iterator may get modified in a big system. In this case, any element may get skipped or read twice based on the implementation of storage data structure.
Mediator Pattern
In our systems, a number of classes exist to complete the functionality and with time, this number tends to increase. With increased number of classes, the major difficulty lies with communication among these classes. To communicate with each other, every class need to be aware about methods of any new/existing class which over the period of time makes the system very unstructured and tangled.
Mediator pattern provides the solution for this problem. It acts as mediator and now this is the only class which actually knows about the methods of all the classes. The classes which need to communicate have to interact with this mediator which further passes on their message to concerned object.
Example
- We have a server side system with a workflow engine. This workflow engine used to execute different workflows based on the request from other components, like an Object Manager can save an object in database and request to this for execute some specific workflow engine. In the same manner, a UI action can request this engine to execute another workflow. This system is very extensible and tends to have a number of other system/application components which need to be interacted with workflow engine. Here one way is to make every component familiar with API of workflow engine and also to make workflow engine familiar with every new component’s API so that it can give the response. But it is very crude and may demand for code changes again and again. Best solution is to define a mediator which can bind the component dynamically and so workflow engine may listen or send the event to any component.
Usage
- Mediator is the only class which knows about other classes, so if any change is required in interface, the corresponding changes have to be done only in mediator.
- Highly flexible system where n Number of new components can be added or removed from the system without actually affecting any API or code change.
- It can produce a ripple effect in the system, even when no component is directly known to any other component. It can propagate the event produced by one component to n number of other components which actually are not a ware about source component but registered for this event.
- It makes loose coupling between the components.
When to Use
- When we need to design a big extensible system where a number of new components are expected in future.
Drawbacks
- Sometimes, it becomes very difficult to track that which even in the system changes the state and who was the originator of this event. So a proper auditing and logging system should be in place before using t his functionality in production.
0 comments:
Post a Comment