Structure of the Chain Of Responsibility pattern

This article is created in continuation of easy patterns series description and presents a behavioral pattern named a Chain Of Responsibility which helps to avoid coupling between sender of a request to its receiver by adding one or more handling objects which have a chance to handle request in specific manner.

Please refer to the other pattern articles as well:

Creational patterns:

Structural patterns:

Behavioral patterns:

Visitor Mediator Observer Memento Iterator Chain Of Responsibility (this article) Strategy State

The main essence

Coupling reduce is achieved by giving more than one object a chance to handle the request consequently. Chain item receiving request and after some logic passes request to the next handler along the handlers chain.

The first object in the chain receives the request and either handles it or forwards it to the next candidate on the chain, which does likewise. The object that made the request has no explicit knowledge who will handle it — the request has an implicit receiver.

This pattern includes two main roles:

Handler — defines an interface for handling requests, handles the request itself and implements the successor link

defines an interface for handling requests, handles the request itself and implements the successor link Client — initiates the request to a Handler object on the chain.

Example of use

In this example we’ll create a coffee machine which contains a set of Handlers which accept coffee cup item to modify and successor link to pass control to the next handler in set. Each coffee cup item includes internal property named ingredientsToBeAdded which you can think like a sticker in the order so barista (coffee machine in our example) know what to add in the coffee. setNewIngredients method will replace a coffee cup with a new one and set new ingredients to be added to it, after that you can processCoffee again with updated ingredients set.

Profit

The Chain of Responsibility pattern is useful if many objects should be able to handle the request and the dedicated handler isn’t known a priori, it will be determined at runtime.

It’s possible not to determine the specific handler for request explicitly, but define a set of potential handlers for this request. This set of objects to handler request can be defined dynamically at runtime. It frees an object from knowing which object handles a request. An object only should to know that a request will be handled appropriately. As a result, Chain of Responsibility can simplify object interconnections.

Added flexibility in assigning respoinsibilities to objects. You can add or change responsibilities for handling a request by adding to or otherwise changing the chain at runtime.

Weak places

The Chain of Responsibility brings some complexity to the logic of handling a specific request. If specific handler set can be defined at runtime, there are many shapes of potential result (we can’t be sure which concrete handler set would appear for specific request). So, there is harder to predict a specific result by planning unit tests.

Since a request has no explicit receiver, there’s no guarantee it’ll be handled at all.

Configuration of the Chain of Responsibility should be made carefully. A request can also go unhandled when the chain is not configured properly.

Conclusion

Currently there are many places where such pattern has found a place. For example in payment logic you should implement different strategies if the user is a holder of several credit cards. In that case we can have a set of strategies and each one will check if it could be applied for a specific banking card.

From the other hand Express (NodeJS) or Redux (lib for handling global application state) have a special place to put an extra logic which is called — middleware. These middleware functions accept current state object and a link to the successor (which passes current state to the next middleware handler in the middleware set).

Chain of Responsibility is often applied in conjunction with Composite pattern. There, a component’s parent can act as its successor.

If you found this article helpful, please hit the 👏 button and feel free to comment below!