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.Logger
andjava.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.