Get up to 80 % extra points for free! More info:

Chain of Responsibility

Chain of responsibility is a design pattern that allows to separate the sender of a request from its one or more recipients. The request is passed from recipient to recipient till it gets to the one competent to deal with it. The implementation should also consider the situation when the recipient is not found.

Motivation

If we tightly connected the class that sends a request and the class that processes it, we'd violate Low Coupling. We'd also lose the possibility to assign multiple handlers processing the request. This is often used in practice when applying various filters that are in a chain, one after another, and process the request somehow, gradually.

The use isn't limited only to linear data structures, but passing the responsibility can also be done at the element-to-parent level in tree structures. Sometimes, the pattern is combined with the Composite pattern, that defines the most efficient way to create such tree structures. This tree can sometimes be referred to as the Tree of Responsibility. Some frameworks use Chain of Responsibility to implement their event models.

Pattern

It's probably not surprising that Handler, the recipient of the request, is defined here as an interface. The sender of the request communicates with this interface and it's implemented by the individual request handlers of the chain or tree. These are connected to each other by references.

The Chain of Responsibility GOF design pattern – UML diagram - GOF - Behavioral Patterns

The handler typically provides methods for setting the next handler. Moreover, the method to handle the request, this method is polymorphic. And finally, the method to pass the request to the next handler. This can happen even if the request was handled only partially or not at all, e.g. because the handler is busy or not competent to handle the request.

Example

There are certainly many examples of Chain of Responsibility, as this is how many services work. For example, when ordering goods from abroad, your request is handled by a chain of post companies. Real practical use, however, is usually the implementation of some filters. These are chained one after another and block the request if it's not valid. Only the last link of such a chain would actually handle the request.

Let's create an example of a chain of such filters. We're gonna filter email requests which will first go through a spam filter, then by a user filter, and then potentially get to the handler that puts them in the inbox folder. Another handler could display a new email notification. Let's make an example of receiving an email that goes through several filters. We'll be able to add and change the filters freely thanks to the pattern.

Let's define the abstraction for the chain handlers:

public abstract class RequestHandler {

    private RequestHandler next;

    public RequestHandler setNext(RequestHandler next) {
        this.next = next;
        return next;
    }

    protected void passToNextHandler(Request request) {
        if (next != null)
            next.handleRequest(request);
    }

    public abstract void handleRequest();

}

Note that the setNext() method returns the next handler in the chain. This is because we can use Method Chaining to put the whole chain together. E.g. this way:

spamFilter.setNext(userFilter).setNext(incommingMailHandler);

We can simply construct the whole chain on a single line. The concrete handlers can look as follows:

public class SpamFilter extends RequestHandler {

    public void handleRequest(Request request) {
        if (!request.Email.Text.Contains("free pills")) { // Simple spam filter
            passToNextHandler(request);
        }
    }

}

public class UserFilter extends RequestHandler {

    public List<String> restrictedAddresses = new ArrayList<String>();

    public void handleRequest(Request request)
    {
        if (!restrictedAddresses.contains(request.email.address)) { // Simple user filter
            passToNextHandler(request);
        }
    }

}

public class IncommingMailHandler extends RequestHandler {

    private IncommingMail mail;

    public IncommingMailHandler(IncommingMail mail) {
        this.mail = mail;
    }

    public void handleRequest(Request request) {
        mail.add(request.email);
    }
}

The features of the individual filters are, of course, extremely simplified and illustrative only. We'd make the whole chain working by passing a request to its first link, SpamFilter.

  • Composite - Chain of responsibility isn't restricted to linear structures and can be also applied to trees, their implementation is the concern of the Composite pattern

 

All articles in this section
GOF - Behavioral Patterns
Article has been written for you by David Capka Hartinger
Avatar
User rating:
No one has rated this quite yet, be the first one!
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities