The original post was published here.
So, three and a half years later… I’m back.
According to wikipedia, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.
In some cases, I will benefit from flexibility allowed by this pattern, without being tied to the chain-based structure, e.g. when there is an IoC container involved: Handlers
in the pattern all have the same interface, so it’s difficult to leave their instantiation to the IoC container.
In such scenario I use a variation of the classic chain of responsibility: there are still responsibilities, off course, but there is no chain out there.
I like to call my variation set of responsibility (or list of responsibility - see above for discussion about this - or selectable responsibility) - the structure is the one that follows (C# code):
1 | interface Handler { |
One interesting scenario which I’ve applied this pattern in is the case in which the Handlers
‘ input type Request
hides a hierarchy of different subclasses and each Handler
implementation is able to deal with a specific Request
subclass: when use polymorphism is not a viable way, e.g. because those classes comes from an external library and are not under our control or they aren’t the best place that to implement the processing logic in, we can use set of responsibility in order to cleanup the horrible code that follows:
1 | class RequestX : Request {} |
We can’t avoid is
and ()
operators usage, but we can hide them behind a polymorphic interface, adopting a design than conform to open-closed principle:
1 | class Sender { |
Adding a new Request
subclass case is now only a matter of adding a new HandlerAA
implemementation of Handler interface, without the need to touch existing code.
I use in cases like the explained one the name of set of responsibility to stress the idea that only one handler of the set can handle a single, specific request (I use _handlers.Single(...)
method in HandlerSet
implementation, too).
When the order in which the handlers are tested matters, we can adopt a different _handlers.Single(...)
strategy: in this case I like to call the pattern variation list of responsibility.
When more than one handler can handle a specific request we can think to variations of this pattern that select all applyable handlers (i.e. those handlers whose CanHandle
method returns true for the current request) and apply them to the incoming request.
So, we have decoupled set/list/chain-processing logic from concrete Request
processing logic, leaving them to vary independently, according to the Single Responsibility Principle, an advantage we would not have adopting the original chain of responsibility pattern…