The Chain of Responsibility pattern is useful when there is a chain of components that need to accomplish the same operation. Each component may have a default implementation and/or cancel the processing chain.
Let’s say we want to write a class that handles http requests. For each request, we want to log it, verify its authentication, and parse the content. Each operation can be designed as a class implementing the same interface.
public interface HttpRequestHandler {
HttpRequestHandler next();
void setNext(HttpRequestHandler next);
// allows to chain other handlers
default void add(HttpRequestHandler handler) {
if (next() != null) {
next().add(handler);
} else {
setNext(handler);
}
};
void process(HttpRequest request);
}
public class Logger implements HttpRequestHandler {
private Log log = ...
private HttpRequestHandler next;
// implements getter/setter
// ...
public void process(HttpRequest request) {
log.log(request); // order can changed if we want the operations to start at the end of the chain
if (next != null) next.process(request);
}
}
public class Authenticator implements HttpRequestHandler {
private HttpRequestHandler next;
// implements getter/setter
// ...
public void process(HttpRequest request) {
if (authenticate(request)) {
if (next != null) next.process(request);
}
// the chain is disrupted if the request does not pass the security check
}
private boolean authenticate(HttpRequest request) {
// ...
}
}
public class Parser implements HttpRequestHandler {
private HttpRequestHandler next;
// implements getter/setter
// ...
public void process(HttpRequest request) {
parse(request);
if (next != null) next.process(request);
}
private void parse(HttpRequest request) {
// ...
}
}
The good thing with this design is that we can add more operations without too much effort. Now we can have our client code manipulating the handlers:
public class WebServer {
public HttpResponse respondTo(HttpRequest request) {
handlers().handle(request);
}
private HttpRequestHandler handlers() {
Logger logger = new Logger();
Authenticator auth = new Authenticator();
Parser parser = new Parser();
logger.add(auth);
logger.add(parser);
return logger;
}
}