This week we’ll continue our exploration of design patterns and look at a very commonly used behavioural pattern, the Chain of Responsibility pattern.
The Chain of Responsibility Pattern
The Gang of Four book defines the Chain of Responsibility pattern as follows:
“Avoid coupling the sender of a request to its receiver by giving more than one object the chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.”
This pattern decouples classes by passing a request from one class to another until the request is recognised. The receiving objects are chained, and the request is passed along the chain until a specific object handles it. Each object in the chain is given a chance to handle the request.
The Chain of Responsibility pattern allows us to define separate handler objects that all conform to a particular interface. This ensures that handlers are independent from each other and loosely coupled.
Chain of Responsibility in the Java APIs
Some examples from the standard Java APIs:
- The Java 1.0 hierarchical event model is an example of Chain of Responsibility. It is now obsolete and used only for backward compatibility.
- Filters in the Servlet API:
javax.servlet.Filter,javax.servlet.FilterChain,javax.servlet.http.HttpFilter. - Interceptors in EJB:
javax.interceptor.Interceptor. - AOP aspects in Spring and other AOP implementations.
- Logical and SOAP handlers with
javax.jws.HandlerChain. - Logging in
java.util.logging.Loggerandjava.util.logging.Handler.
Chain of Responsibility: Example Problem
In our first person shooter game, we’ve already sent out a desperate call to headquarters (HQ) for reinforcements. There could be any number of calls coming in with other requests: food and supplies, medical assistance, aerial support to bomb a target, even evacuations. This game is getting a bit too real!
If we had one method handling all of these different requests, we would have a series of if...else statements that would not be particularly object-oriented, and to top it, would be tedious to modify, maintain and test. Some example code follows:
public class HeadQuarters {
public void processRequest (String request) {
// check the incoming request string for null,
// then call trim() and toUpperCase() on it.
if (request.contains("FOOD")) {
// respond with food delivery
}
else if (request.contains("MEDIC")) {
// respond with medicine and doctors
}
else if (request.contains("AERIAL")) {
// respond with aerial support bombers
}
else if (request.contains("EVAC")) {
// respond with evacuation helicopter
}
else
// stand by for the first available operator...
}
// other code not shown
} // end of class
There must be a better way than this, surely!
Chain of Responsibility: Example Solution
Chain of Responsibility to the rescue! Let’s create a series of handlers, each of which will respond to a specific request. We will chain these handlers together, passing the request from one handler to another until the request is dealt with. If a specific handler can’t handle the request, it passes it on to the next handler in the chain.
First of all, we create an interface for the handlers:
public interface RequestHandler {
public void processRequest(String request);
public void setNextHandler(RequestHandler handler);
} // end of class
We’ll also create an AbstractRequestHandler class to provide appropriate default behaviour for the RequestHandler interface:
public abstract class AbstractRequestHandler implements RequestHandler {
private RequestHandler nextHandler;
@Override
public void setNextHandler(RequestHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void processRequest(String request) {
boolean match = false;
// Handle the request here if the word list is empty
if (wordList().length == 0) {
match = true;
} else {
// Search for any of the keywords
for (String word : wordList()) {
if (request.indexOf(word) >= 0) {
match = true;
break;
}
}
}
// Can we handle the request here?
if (match) {
handleRequest(request);
} else {
// No match so pass the request along the chain
nextHandler.processRequest(request);
}
}
// to be implemented by the concrete handler subclasses
protected abstract String[] wordList();
protected abstract void handleRequest(String request);
} // end of class
The setNextHandler() method is passed a RequestHandler which is the next handler to call if the current handler can’t respond to the request.
The processRequest() method takes the request as its argument. It compares the incoming request with the list of keywords set up in the wordList() method. If any of these words are contained in the request string, then the active handler can respond to the request. If there isn’t a word match, then the active handler passes the request to the next handler in the chain.
The wordList() and handleRequest() methods are appropriately implemented by the concrete handler subclasses as follows:
public class FoodRequestHandler extends AbstractRequestHandler {
protected String[] wordList() {
return new String[]{"food", "water", "rations", "hungry"};
}
protected void handleRequest(String request) {
System.out.println("Request handled by kitchen.");
}
}
public class MedicRequestHandler extends AbstractRequestHandler {
protected String[] wordList() {
return new String[]{"medic", "medicine", "doctor"};
}
protected void handleRequest(String request) {
System.out.println("Request handled by medical department.");
}
}
public class EvacuationRequestHandler extends AbstractRequestHandler {
protected String[] wordList() {
return new String[]{"evac", "evacuation"};
}
protected void handleRequest(String request) {
System.out.println("Request handled by evacuations.");
}
}
public class AerialSupportRequestHandler extends AbstractRequestHandler {
protected String[] wordList() {
return new String[]{"bombing", "aerial"};
}
protected void handleRequest(String request) {
System.out.println("Request handled by aerial support.");
}
}
public class OperatorRequestHandler extends AbstractRequestHandler {
protected String[] wordList() {
return new String[0]; // match anything
}
protected void handleRequest(String request) {
System.out.println("Request handled by operator.");
}
}
A client class using the handlers could be written as follows. To help set up the request handler chain, we could add a static method to the client class:
public class ChainOfResponsibilityClient {
public static RequestHandler getHandlerChain(){
// Create the handlers
RequestHandler food = new FoodRequestHandler();
RequestHandler medic = new MedicRequestHandler();
RequestHandler evac = new EvacuationRequestHandler();
RequestHandler aerial = new AerialSupportRequestHandler();
RequestHandler operator = new OperatorRequestHandler();
// Chain them together
food .setNextHandler(medic);
medic .setNextHandler(evac);
evac .setNextHandler(aerial);
aerial.setNextHandler(operator);
return food; // Start of the handler chain
}
public static void main (String args[]) {
RequestHandler chain = getHandlerChain();
String request = "We need aerial support!";
System.out.println(request);
chain.processRequest(request);
request = "We're hungry!";
System.out.println(request);
chain.processRequest(request);
request = "We're lost and confused!";
System.out.println(request);
chain.processRequest(request);
}
} // end of class
Obviously in a production environment it would be more flexible to set up the chain using an external configuration mechanism (such as XML) rather than in code which would need to be recompiled each time we added or removed a handler from the chain.
Comparison with Other Design Patterns
Other patterns such as Command, Mediator and Observer also decouple the objects making the requests from the objects receiving them, but they all implement it in different ways. Chain of Responsibility uses a chain of handlers to process the request.
Patterns can be combined to create flexible code. For example, the Command pattern can be used to wrap the request, and Chain of Responsibility can decouple the requests from their handlers.
As always, please share your comments and questions.