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:
- 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
- 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.
- 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.
- 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