Browser docs

Chain of responsibility

Intent

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Explanation

Real-world example

The Orc King gives loud orders to his army. The closest one to react is the commander, then an officer, and then a soldier. The commander, officer, and soldier form a chain of responsibility.

In plain words

It helps to build a chain of objects. A request enters from one end and keeps going from an object to another until it finds a suitable handler.

Wikipedia says

In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.

Programmatic Example

Translating our example with the orcs from above. First, we have the Request class:

 1public class Request {
 2
 3  private final RequestType requestType;
 4  private final String requestDescription;
 5  private boolean handled;
 6
 7  public Request(final RequestType requestType, final String requestDescription) {
 8    this.requestType = Objects.requireNonNull(requestType);
 9    this.requestDescription = Objects.requireNonNull(requestDescription);
10  }
11
12  public String getRequestDescription() { return requestDescription; }
13
14  public RequestType getRequestType() { return requestType; }
15
16  public void markHandled() { this.handled = true; }
17
18  public boolean isHandled() { return this.handled; }
19
20  @Override
21  public String toString() { return getRequestDescription(); }
22}
23
24public enum RequestType {
25  DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
26}

Next, we show the request handler hierarchy.

 1public interface RequestHandler {
 2
 3    boolean canHandleRequest(Request req);
 4
 5    int getPriority();
 6
 7    void handle(Request req);
 8
 9    String name();
10}
11
12@Slf4j
13public class OrcCommander implements RequestHandler {
14    @Override
15    public boolean canHandleRequest(Request req) {
16        return req.getRequestType() == RequestType.DEFEND_CASTLE;
17    }
18
19    @Override
20    public int getPriority() {
21        return 2;
22    }
23
24    @Override
25    public void handle(Request req) {
26        req.markHandled();
27        LOGGER.info("{} handling request \"{}\"", name(), req);
28    }
29
30    @Override
31    public String name() {
32        return "Orc commander";
33    }
34}
35
36// OrcOfficer and OrcSoldier are defined similarly as OrcCommander

The Orc King gives the orders and forms the chain.

 1public class OrcKing {
 2
 3  private List<RequestHandler> handlers;
 4
 5  public OrcKing() {
 6    buildChain();
 7  }
 8
 9  private void buildChain() {
10    handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier());
11  }
12
13  public void makeRequest(Request req) {
14    handlers
15        .stream()
16        .sorted(Comparator.comparing(RequestHandler::getPriority))
17        .filter(handler -> handler.canHandleRequest(req))
18        .findFirst()
19        .ifPresent(handler -> handler.handle(req));
20  }
21}

The chain of responsibility in action.

1var king = new OrcKing();
2king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
3king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner"));
4king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));

The console output.

Orc commander handling request "defend castle"
Orc officer handling request "torture prisoner"
Orc soldier handling request "collect tax"

Class diagram

alt text

Applicability

Use Chain of Responsibility when

  • More than one object may handle a request, and the handler isn’t known a priori. The handler should be ascertained automatically.
  • You want to issue a request to one of several objects without specifying the receiver explicitly.
  • The set of objects that can handle a request should be specified dynamically.

Known uses

Credits