Java programming language logo

Chain of Responsibility Design Pattern

The Chain of Responsibility pattern defines a chain of request handlers. The requests are passed to the first handler in the chain. If a request can be handled by a handler, then it processes it and quits; otherwise, it passes the request to the next handler.

In some implementations, after a request is processed by a proper handler, it doesn't quit from the chain, instead of it passes the request to the next handler. In this case, a request can be processed by multiple handlers.

A typical example for this can be a logger. For example, a file logger and a console logger also process the requests and not just one of them prints out the messages.

Other example, when the request process quits, can be an email handler that places the incoming e-mails into different folders. If one of the handlers can move it into the right folder, it makes no sense to pass the request to a next handler. See the detailed example below.

Every handler in the chain have to implement the same interface or extend the same base class, and have a reference to the next handler. They all do the same steps: try to process the request and call the next handler if needed.

This design is very flexible. New handlers can be added to the chain easily without breaking the existing code. Furthermore, it can also be added at run-time.

Chain of Responsibility is a behavioral pattern.

Example

Let’s see a Java example for the Chain of Responsibility pattern.

The next example handles incoming e-mails. It defines a chain of e-mail handlers. The e-mail passed to the first handler that examines it. If it can handle, then it does. If not, it passes the e-mail to the next handler. For example, if the e-mail is passed to the spam handler, and it seems to be a spam, it gets to the spam folder.

The Email instances will be processed by the handlers. For the shake of simplicity, it only contains the sender (from), the subject and the message. The addressee is omitted now because it is unused.


package com.programcodex.designpatterns.chainofresponsibility;

public class Email {

    private final String from;
    private final String subject;
    private final String message;

    public Email(String from, String subject, String message) {
        this.from = from;
        this.subject = subject;
        this.message = message;
    }

    public String getFrom() {
        return from;
    }

    public String getSubject() {
        return subject;
    }

    public String getMessage() {
        return message;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("\nEmail from ").append(from)
        .append("\nSubject: ").append(subject)
        .append("\nMessage: ").append(message)
        .append("\n\n");
        return sb.toString();
    }
}

All handler class in the chain extends the BaseHandler abstract class. It contains a reference to the next handler in the chain. The next handler can be passed to the constructor at instantiation, or it can be set later by the setNextHandler method. If the next handler has already been set, then the next handler’s setNextHandler method is called.

It also has a default constructor, which means setting the next handler is optional. At the end of the chain the nextHandler field remains null.

The request is processed by the processRequest method. It receives an e-mail, and the accept method examines whether this class could handle it. If it can handle, then it does by the process method. If not, and there is another handler, then it passes the e-mail to the next one.

The accept and process methods are abstract, the subclasses have to implement them.


package com.programcodex.designpatterns.chainofresponsibility;

public abstract class BaseHandler {

    private BaseHandler nextHandler;

    public BaseHandler() {
    }

    public BaseHandler(BaseHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void setNextHandler(BaseHandler nextHandler) {
        if (this.nextHandler == null) {
            this.nextHandler = nextHandler;
        } else {
            this.nextHandler.setNextHandler(nextHandler);
        }
    }

    public void processRequest(Email email) {
        if (accept(email)) {
            process(email);
        } else if (nextHandler != null) {
            nextHandler.processRequest(email);
        } else {
            System.out.println("No handler for this.");
        }
    }

    protected abstract boolean accept(Email email);

    protected abstract void process(Email email);
}

The JohnDoeHandler class extends the BaseHandler class. This is an actual handler with a concrete responsibility. It checks the sender of the e-mail, and if it comes from John Doe, then it moves it to the appropriate folder.

This class implements the accept and process methods. The accept method checks the sender of the e-mail, and if it returns with true, then the process method arranges it.


package com.programcodex.designpatterns.chainofresponsibility;

public class JohnDoeHandler extends BaseHandler {

    public JohnDoeHandler() {
    }

    public JohnDoeHandler(BaseHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    protected boolean accept(Email email) {
        System.out.println("Is it from John Doe?");
        
        return email.getFrom().contains("john.doe");
    }

    @Override
    protected void process(Email email) {
        System.out.println("Yes, moved to John Doe folder.");
    }
}

The SpamHandler moves the e-mail to the spam folder, if it seems to be one.

In this very simple example, an e-mail is considered to be spam if it contains a concrete expression. Of course in real life this wouldn’t be a sufficient solution. Now it only shows a different implementation for the accept method.


package com.programcodex.designpatterns.chainofresponsibility;

public class SpamHandler extends BaseHandler {

    public SpamHandler() {
    }

    public SpamHandler(BaseHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    protected boolean accept(Email email) {
        System.out.println("Is it spam?");

        String lowSub = email.getSubject().toLowerCase();
        String lowMsg = email.getMessage().toLowerCase();
        return lowSub.contains("you won")
                || lowMsg.contains("you won");
    }

    @Override
    protected void process(Email email) {
        System.out.println("Yes, moved to Spam folder.");
    }
}

The DailyReportHandler class examines the subject of the e-mail, and if it starts with the "Daily Report" words, then handles it.


package com.programcodex.designpatterns.chainofresponsibility;

public class DailyReportHandler extends BaseHandler {

    public DailyReportHandler() {
    }

    public DailyReportHandler(BaseHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    protected boolean accept(Email email) {
        System.out.println("Is it a Daily Report?");

        return email.getSubject().startsWith("Daily Report");
    }

    @Override
    protected void process(Email email) {
        System.out.println("Yes, moved to Daily Report folder.");
    }
}

And we are done. It’s time to run these things.

The emails list contains Email instances.

In the main method a SpamHandler is instantiated, and a JohnDoeHandler instance is passed to it as an argument. So the next handler of the SpamHandler instance is a JohnDoeHandler instance.

In the next line, the DailyReportHandler is added to the chain. This demonstrates that handlers also can be added to the chain later.

Finally, each email is passed to the handler instance.


package com.programcodex.designpatterns.chainofresponsibility;

import java.util.ArrayList;
import java.util.List;

public class TestChainOfResponsibility {

    private static List<Email> emails;
    
    static {
        emails = new ArrayList<>();
        emails.add(new Email("john.doe@me.com",
                "Hello", "Hello World!"));
        emails.add(new Email("noreplay@company.com",
                "Daily Report 158", "Great news!"));
        emails.add(new Email("dark@ad.com",
                "You WON!!!", "You are lucky"));
        emails.add(new Email("some@body.com",
                "An average email", "No handler for this one."));
    }
    
    public static void main(String[] args) {
        BaseHandler handler = new SpamHandler(new JohnDoeHandler());
        
        // More handler can be added at run-time.
        handler.setNextHandler(new DailyReportHandler());
        
        receiveMails(handler);
    }
    
    private static void receiveMails(BaseHandler handler) {
        emails.forEach(email -> {
            System.out.println("\n################################");
            System.out.print(email);
            handler.processRequest(email);
        });        
    }
}

The output of the above test class:

The Chain of Responsibility Design Pattern