As the name suggests Chain of responsibility design pattern creates/describes a chain of responsibility. This chain can be static/hardcoded or it can be dynamic and loaded or changed at run-time. It is in many ways a more object oriented cleaner way to implement if/else or switch statement. With the additional benefit of it being able to be dynamically loaded.
The easy way to describe it would be to consider a scenario of first day in high school. Everyone sits in a circle and the teacher sends a bag with nametags around. The task is easy everyone takes the nametag with their name on it and then passes the bag along again. In this scenario, your responsibility is your nametag, which you grab, and then you pass along to the next link in the chain.
It could also be a scenario where your teacher asks you to put your names on a list of courses that you wanted to attend. She passes along a few lists with courses and you put your name on the lists (courses) you want, and then, passes the lists along to the next in line.
The dynamic loading equivalent of this scenario would be your teacher asking all who wants to attend philosophy raise their hand and then pass the list to the first in line, which should enter their name and then pass it along to the next one with their hand raised.
It is as simple as that.
However, for this to make sense in a programming scenario and add clarity and cleanliness instead of overhead and complexity, we need to make good use of generics. I want to explain how we can use it as a clean way of handling responses from for instance API calls.
A prerequisite for doing this in a clean way will be base classes for request/response classes. This is required in order to implement a ResponseChainHandlerBase-class that can be used across all requests/responses. Then we can centralize the generic part of the handling and only create concrete implementations to handle the specific cases.
First, we will create an interface for response-chain handlers.
This interface will, as shown, use our RequestBase and ResponseBase as generics and have two methods. CallAndHandleResponse that takes a request, the request-funtion and a retry-function as parameters. More on these last two func-parameters later. Then it has SetNextHandler medthod, which as the name suggests, sets the next handler in the chain.
With this in place, we can implement the abstract base class that all response-chain handlers has to inherit from. The implementation of the ResponseChainHandlerBase will be as shown below, with further explanation underneath it.
From top of the class, we have a request function (CallFunc), which as the name suggests, is the function that will be called with the request and return the response. Then we have the SetNextHandler that sets the next handler in the chain.
Then there is the public CallAndHandleResponse – which is the “public” entry point of calling our handlers. As you can see from the implementation it calls the function from the method body, with the request (also from method body) and then it calls the function via CallFunc passing along the retryFunc from method body. The reason for having this is that we want the response handlers to be able to re-try a call. But, the response-handler should not be allowed to decide whether re-try is allowed or not. This is the responsibility of the class that uses the response chain. Therefore we have this retryAllowedFunc passed along as parameter.
If response is not null then it calls the HandleResponse on the implementing class and if there are more classes after this, then it will call the next in line afterwards.
Finally there is the abstract HandleResponse method that the implementing class will have to implement and enrich.
With our interface and base class in order, we will turn our attention to the implementation of a concrete response handler.
The specific use case where this came into play was a system doing calculations. This system sat on top of a stateless calculator and managed the flow. Depending on input for the calculator, there were scenarios, where the calculator would return error if calculation was done with insurance included. In these cases the end-user would then be required to un-select insurance – if that was allowed for the product – and then calculate again to get a valid quote.
Therefore, there was a need to build some logic that could handle this retry automatically. As there are many other “add-on” services related to the calculations, I also knew that this would be a good candidate for a general pattern for how response-handling should be done.
Hence, the chain of responsibility pattern looked like a good fit. We could have a number of handlers that each had their own narrow responsibility and we could then apply them as needed either by themselves or in combination.
So now, with a bit of context, let us look at a concrete implementation of the InsuranceResponseChainHandler:
The logic of this handler is very simple. It looks at the ErrorCode returned and if it is one of the ErrorCodes that are insurance-related, then it will try to de-select insurance. However, as some products does not allow this, we call the retryAllowedFunc passed into the method. If allowed we call the CallFunc method on the ResponseChainHandlerBase. With this, our InsuranceResponseChainHandler is complete. It can re-try if ErrorCode returned is one of the ones specific to insurance. This list of ErrorCodes can of course be fetched from config, set-up dynamically depending on request-type etc. Nevertheless, for our use this private readonly HashSet was sufficient.
Now let us look at how this chain handler pattern is actually used.
We will start with the Factory that creates the chain. This could be done with other dependency-injection patterns, but for this scenario, we use factories.
The most interesting part for explaining the chain handler pattern is the part to do with _responseChainHandler. In this factory we instantiate the InsuranceResponseChainHandler class that we created above. However, reading through the comments below I also show how we could easily add more handlers after this one. As you will probably also have noticed we could dynamically have built this chain depending on the type of request or whatever else might determine the correct “chain”.
Having now injected the response chain handler into our “Manager”, which shortly described for this piece, is the class that manages the flow around calculations, we can call it with just a single line of code:
The parameters supplied to the CallAndHandleResponse are in order of appearance:
- The internalRequest – in this case a “calculation-request”
- (_calculateInternalEngine.CallCalculateInternal) The “business engine” class that actually calls the “calculator”. (This is our CallFunc from earlier)
- (ValidInternalRetryRequest) A method residing in the “Manager” that decides whether retry is allowed. In our scenario, it will validate whether the product we are calculating upon actually allows IncludeInsurance to be set to false and then returns true or false. (This is our retryAllowedFunc from earlier)
With this, the response chain handler pattern is complete. We have created a dynamic and extendable way of handling responses from either internal API’s, external API’s or a way for handling responses from internal validators or classes – the use-cases are vast.
Happy coding and “architecturing“