As Aerosmith sang many years ago, “Code looks like a Chain.” No? They didn't say that? Maybe I'm remembering it wrong. Well, as you might have guessed, in this post, we'll talk about the Chain of Responsibility design pattern. This pattern is not one of the more popular ones, at least among the patterns defined by the Gang of Four, but modern dependency injection frameworks give us the possibility to implement it in a smart, and fresh way. Let’s see how.

Introduction

Disclaimer: There is nothing new with this pattern. A colleague of mine used it days ago, and I've also used it a lot in the past. This post was inspired by a solution to a problem I recently encountered, which we'll dive into below, and I did not immediately notice that this pattern could be used to solve that problem.

The Classic Pattern

The Chain of Responsibility pattern is a behavioral design pattern. It was first defined in the book Design Patterns, written by the Gang of Four. The intent of the pattern is to:

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.

The class diagram relative to the pattern is as follows:

Loose coupling is accomplished through the definition of a standard interface by which we can respond to clients’ requests. In the above diagram, it is represented by the abstract type Handler. The ability to have more than one object respond to a request is simply accomplished by creating a chain of objects that implement the above interface. Each object owns an instance of the next link in the chain. The successor attribute satisfies this scope.

When called, each handler verifies whether it is able to respond to the request. If it can, it performs the operations requested. At this point, we can have many different implementations, which differ by the request forward policy. We can implement a policy that stops the request in the chain once a ConcreteHandler has stated that can handle it. In this case, the implementation of the handleRequest method will be the following:

The Advent of Dependency Injection

As in many other situations, the definition of the dependency injection pattern changed the tune. Let’s see how to use DI features to modernize the Chain of Responsibility pattern.

First of all, we need a feature that, in some ways, all the DI libraries implement: multibindings. Basically, using this feature, it is possible to provide an instance of all subtypes of a type, simply by trying to inject a collection of that type.

Now, we will define a new type ShoppingCenter, that owns an instance of all subtypes of Shop. Using dependency injection, we can achieve these goals simply by injecting a collection of Shop inside ShoppingCenter.

Simple as f**k! Obviously, every dependency injection library has its own ways to configure the injector to resolve such a situation. In Spring, using the auto-discovery feature, you have to do very little configuration. In Guice, the story is a little more complicated, but the final result is the same.

Modern Implementations of CoR

To summarize a little: We have seen the Chain of Responsibility design pattern in its classical form; we have seen the multibindings feature provided by dependency injection libraries; in the final step to nirvana, we will see how to mix these two concepts together.

First of all, we need a slightly different implementation of the original CoR design pattern. Let’s introduce a new type, the ChainHandler. The responsibility of this type is to own the whole chain and to expose a single point of access to the functions offered by the chain itself to the clients.

Taking advantage of dependency injection, adding a new Handler implementation requires no changes in the existing code at all. This means that virtually no regression tests need to be performed. On the other hand, it is a little bit more difficult (but not impossible) to impose an order of execution of Handlers inside the chain.

Warnings

As in many other patterns, it is important to focus on what the roles of the classes that build the pattern are. Which responsibilities will you give to a concrete Handler? Will you develop the business logic of the application directly inside the body of that Handler?

At first, many of us would provide the above solution. It is not inherently wrong. However, this kind of design limits the reusability of the code and violates the famous Single Responsibility Principle.

For example, let’s imagine that we have to implement a system that enriches the information of a financial transaction. The enrichment process is developed using the CoR pattern. One of the possible enrichments could be the insertion of the payee country derived from an IBAN or a BIC code. Then, let’s defined a CountryPayeeEnricher.

At a first glance, one could be tempted to insert the code that extracts the country information directly inside the body of the CountryPayeeEnricher class. But what if we have to reuse this function in another point of our application (or in another application at all)? It is a far better solution to resume the composition principle, putting the code inside a dedicated type, let’s say PayeeService.

In this way, we end up with two types with different responsibilities: There's the PayeeService type, which offers reusable services directly connected to payee information, and the CountryPayeeEnricher type, which offers standardized access to the services offered by the previous type.

The Scala Way

For the sake of completeness, I also want to talk about the implementation of the CoR pattern in the Scala language. As with many other design patterns, there is an implementation of the CoR pattern built into the language: partial functions. As the theory states, a partial function is a function that is defined only for some subset of values of its domain. In Scala, such functions have a specific type — PartialFunction[T, V].

Partial functions in Scala are defined using pattern matching statements. In the following example, the value fraction is not defined for a zero value.

If there are multiple definition sets, you can have more than one case clause. If you think of every case clause as a condition to satisfy in order to apply a function (the handler in CoR, do you see it?), you get the CoR pattern again.