Applied Design Patterns with Java

Behavioral :: Chain of Responsibility (223) {C ch 16}

Implementation

Here are implementation issues to consider when using the Chain of Responsibility pattern:

  1. Implementing the successor chain. There are two possible ways to implement the successor chain: define new links (usually in the Handler, but ConcreteHandlers could define them instead), or use existing links. It is possible to use existing object references to form the successor chain. Parent references in a part-whole hierarchy can define a part's successor. A widget structure might already have such links. Composite (163) discusses parent references in more detail. Using existing links works well when the links support the chain needed. It saves from defining links explicitly, and it saves space. But if the structure doesn't reflect the chain of responsibility required, it will be necessary to define redundant links
  2. Connecting successors. If there are no preexisting references for defining a chain, it may be necessary to introduce them. In that case, the Handler not only defines the interface for the requests but usually maintains the successor as well. That lets the handler provide a default implementation of HandleRequest that forwards the request to the successor (if any). If a ConcreteHandler subclass isn't interested in the request, it doesn't have to override the forwarding operation, since its default implementation forwards unconditionally.
  3. Representing requests. Different options are available for representing requests. In the simplest form, the request is a hard-coded operation invocation, as in the case of HandleHelp. This is convenient and safe, but it only allows forwarding the fixed set of requests that the Handler class defines. An alternative is to use a single handler function that takes a request code (e.g., an integer constant or a string) as parameter. This supports an open-ended set of requests. The only requirement is that the sender and receiver agree on how the request should be encoded. This approach is more flexible, but it requires conditional statements for dispatching the request based on its code. There's no type-safe way to pass parameters, so they must be packed and unpacked manually. This is less safe than invoking an operation directly. To address the parameter-passing problem, use separate request objects that bundle request parameters. A Request class can represent requests explicitly, and new kinds of requests can be defined by subclassing. Subclasses can define different parameters. Handlers must know the kind of request (that is, which Request subclass they're using) to access these parameters. To identify the request, Request can define an accessor function that returns an identifier for the class. Alternatively, the receiver can use run-time type information if the implementation languages supports it.
  4. Automatic forwarding in Smalltalk. This capability does not exist in Java.


Related Patterns

Chain of Responsibility is often applied in conjunction with Composite (163). There, a component's parent can act as its successor.

Catalog Behavioral Prev Next