In this part of article series for "Software patterns- GRASP", we would explore the process of assigning responsibilities so has to combine the low coupling and potential for reuse.
To understand the GRASP pattern “Indirection”
We have explored what are patterns and GRASP (in part I), Information Expert in part II and Creator in part II, Controller in Part IV, “Low Coupling” in part V and “High Cohesion” in part VI and Polymorphism in Part VII, Pure Fabrication in Part VIII. In this part IX, we would focus on next GRASP pattern named “Indirection”.
The dictionary meaning of indirections is “indirect procedure or action” or “Deceitful action that is not straightforward”. This meaning is straightforward to understand and relate. This means that some action would not be taken directly by the object in question but it would be performed by intermediately object which can be used by different other object who needs similar action.
The principle behind this pattern is “How one can decouple the objects so that the Low Coupling is supported and the potential for reuse remains high?”
Problem: How to combine Low coupling and high potential for reuse?
Solution: Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled.
Step I: Closely look at domain/ design model and locate the classes with low coupling or direct coupling e.g.
Step II: Use an existing class to take the responsibility of functionality causing low coupling and also the functionality has high potential for reuse.
In a nutshell, “Assign the responsibilities to an intermediate object which in turn collaborates with two objects avoiding the directly coupling i.e. indirection”.
In the last article we have seen the pure fabrication and we would wonder its one and the same. Rather It is often a pure fabrication with only difference being that pure fabrication also focuses on handling the low cohesion rather than reuse.
Let’s extend an example of POS (Point Of Sale) systems explained in previous part. The example for “Pure Fabrication” is valid for indirection too. The large number of database operations, are generally common for different domain objects which motivates to assign the responsibility of database operations to an intermediate object decoupling the database and domain objects. This would result in very general classes which can be used by many objects. The solution is to create a new class say “PersistentStorageBroker“which would interact with database interface and saves the instance of “Sale” class. As “Sale” would be spared from saving its own instance into database thus giving rise to high cohesion and low coupling. In this fashion the “PersistentStorageBroker” is also highly cohesive by performing the sole responsibility of saving the instance / object. (Right part of Fig no.1 i.e. “Design II”)
Fig No. 1
Table No. 1
Relationship with other classes
Responsibility and method
Call upon the PersistentStorageBroker- delegates the responsibility to perform database operations
To represent a particular “Sale”
A separate class having unique responsibility of saving the objects to database. This can be utilized by other classes like “Register”, “Payment” etc or even the outside the domain as its generic.
Saving the objects to database through “InsertToDatabase()”
Adds a level of indirection be decoupling the domain class and database services.
As demonstrated, the “PersistentStorageBroker” is a generic and reusable class. Another example would be of a device MODEM through which the credit payment authorization would take place in POS. Imagine a “CreditPayementAuthorizationService” responsible for talking to modem device. This invokes low level API’s. In case of different OS, this class would require modifications in the service. If we introduce a level of indirection i.e. a Modem class which would translate the abstract authorization request to API’s
Fig No. 2
This way the direct coupling among the service and API's is avoided resulting into low coupling and also potential for reuse of modem class.
Related Patterns and examples:
The publisher subscriber or observer patterns are examples of indirection.
Commonly, the Indirection is used to place / encapsulate the algorithm or function which doesn’t fit well in other classes.
· Supports Low Coupling
· Results in high reusability
· Sometimes such design may result into bunch of classes having a single method which is a kind of overkill.
Summary & Conclusion
In this part, we discussed what Indirection is and also the principle behind this. The steps for assigning responsibility for implementation "Indirection" were mentioned. We continued with practical example from POS the (Point Of Sales) and explanation for having Indirection. Particularly, we saw an example of “PersistentStorageBroker”. The benefits and contradiction are mentioned which are similar to "Pure Fabrcation". This pattern is kind of “Pure Fabrication” with difference in objective of achieving decoupling. This is generally to break the coupling in objects and different components and services and serves as an intermediate object.
To reiterate, following/ employing patterns for design would result into highly maintainable, robust and reusable systems.
Applying UML and Patterns