Listen to this post
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it. (GoF)
A provider of retirement accounts and mutual funds could provide a web-based service allowing their customers to check on the current status of their investments on demand. The customers would be interested in knowing the most up-to-date information on how the stocks, bonds, and other instruments in their fund were currently priced by the market.
If there were several strategic partners that might be able to resolve a given financial symbol and “the right one” might change unpredictably, a Chain of Responsibility could be implemented to allow the request to flow from one provider to another until the answer was found.
Qualities and principles
Each member of the chain is focused on one version of the request. The clients are coupled to the service interface. The number of services, how they are selected, and the order in which they are given a chance are all encapsulated. New services can be added, removed, and reordered within the chain. All redundancies can be pulled up into the base class. Dependencies between the services are inherently captured in the chain’s order.
Tests can be made sub-classes of the service objects. Each service object can have two tests: one proving the object selects when it should and another proving the behavior is correct.
Questions and concerns
What should happen if none of the objects in the chain can complete the request? This is a decision to be made on a case-by-case basis. The typical implementation of the Chain of Responsibility is a linked list, but in fact, any collection can be used and scanned in any way desired. A Template Method, getValue() in the example, is typically used to implement this pattern internally, to keep the “next” pointer private and to avoid redundantly implementing the “handoff to the next object” action.