From "Design Patterns"
🎧 Listen to Summary
Free 10-min PreviewChain of Responsibility Pattern
Key Insight
The Chain of Responsibility pattern decouples the sender of a request from its receiver by allowing multiple objects a chance to handle the request. The request propagates along a chain of objects until one handles it, meaning the sender has no explicit knowledge of the ultimate receiver. For example, in a context-sensitive help system for a graphical user interface, clicking a button initiates a help request. The help information provided depends on the specific UI element and its context, such as a 'Print' button inside a 'PrintDialog' versus a similar button in a main window. If no specific help exists, a more general message for the immediate context (e.g., the dialog) is displayed. The problem solved is that the initiating object (the button) does not explicitly know which object in the hierarchy will provide the help. The request implicitly traverses the chain, for instance, from `aPrintButton` to `aPrintDialog` and then to `anApplication`, until a handler is found or the chain ends.
The pattern's structure involves objects on the chain sharing a common `Handler` interface, defining how to handle requests and access a successor. For instance, a `HelpHandler` class might define a `HandleHelp` operation, which subclasses (like `Button`, `Dialog`, `Application`) can override for specific processing, or use a default implementation to forward the request. This pattern is applicable when more than one object can handle a request and the handler is not known a priori, when requests need to be issued to one of several objects without specifying the receiver explicitly, or when the set of potential handlers should be dynamically configurable. Participants include the `Handler` (interface for requests, optional successor link), `ConcreteHandler` (handles specific requests, forwards others), and `Client` (initiates the request). Key consequences include reduced coupling between sender and receiver, increased flexibility in assigning responsibilities by dynamically altering the chain, and the liability that a request is not guaranteed to be handled, potentially falling off the end of the chain if no object takes responsibility or if the chain is misconfigured.
Implementation considerations include how to establish the successor chain, either by defining new links within `Handler` or `ConcreteHandler` classes, or by leveraging existing object references such as parent references in a part-whole hierarchy. If new links are required, the `Handler` typically maintains the successor and provides a default `HandleRequest` that unconditionally forwards. Requests can be represented in several ways: hard-coded operation invocations (convenient but fixed set), a single handler function taking a request code (flexible but requires conditional dispatch and manual parameter handling, less type-safe), or separate request objects that encapsulate parameters. Request objects, often identified by an accessor function or run-time type information, allow handlers to process specific request types and forward others, effectively extending the `HandleRequest` operation. In Smalltalk, the `doesNotUnderstand` mechanism can automate forwarding. An example online help system demonstrates `HelpHandler` as an interface, with `Widget` as a subclass for UI elements, and `Button`, `Dialog`, and `Application` implementing or forwarding `HandleHelp` based on their context and assigned help topics, allowing dynamic changes to the chain.
📚 Continue Your Learning Journey — No Payment Required
Access the complete Design Patterns summary with audio narration, key takeaways, and actionable insights from Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.