Here are implementation issues to consider in Chain of Responsibility:
Our examples so far define new links, but often you can use existing object references to form the successor chain. For example, parent references in a part-whole hierarchy can define a part's successor. A widget structure might already have such links. Composite discusses parent references in more detail.
Using existing links works well when the links support the chain you need. It saves you from defining links explicitly, and it saves space. But if the structure doesn't reflect the chain of responsibility your application requires, then you'll have to define redundant links.
Here's a HelpHandler base class that maintains a successor link:
class HelpHandler { public: HelpHandler(HelpHandler* s) : _successor(s) { } virtual void HandleHelp(); private: HelpHandler* _successor; }; void HelpHandler::HandleHelp () { if (_successor) { _successor->HandleHelp(); } }
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. Moreover, there's no type-safe way to pass parameters, so they must be packed and unpacked manually. Obviously this is less safe than invoking an operation directly.
To address the parameter-passing problem, we can 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.
Here is a sketch of a dispatch function that uses request objects to identify requests. A GetKind operation defined in the base Request class identifies the kind of request:
Subclasses can extend the dispatch by overriding HandleRequest. The subclass handles only the requests in which it's interested; other requests are forwarded to the parent class. In this way, subclasses effectively extend (rather than override) the HandleRequest operation. For example, here's how an ExtendedHandler subclass extends MyHandler's version of HandleRequest:void Handler::HandleRequest (Request* theRequest) { switch (theRequest->GetKind()) { case Help: // cast argument to appropriate type HandleHelp((HelpRequest*) theRequest); break; case Print: HandlePrint((PrintRequest*) theRequest); // ... break; default: // ... break; } }
class ExtendedHandler : public Handler { public: virtual void HandleRequest(Request* theRequest); // ... }; void ExtendedHandler::HandleRequest (Request* theRequest) { switch (theRequest->GetKind()) { case Preview: // handle the Preview request break; default: // let Handler handle other requests Handler::HandleRequest(theRequest); } }