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.
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: