Chain f Respnsibility 1 Intent Avid cupling the sender f a request t its receiver by giving mre than ne bject a chance t handle the request. Chain the receiving bjects and pass the request alng the chain until an bject handles it. Mtivatin A cntext-sensitive help facility fr a graphical user interface. The prblem here is that the bject that ultimately prvides the help isn't knwn explicitly t the bject (e.g., the buttn) that initiates the help request. The bject that made the request has n explicit knwledge f wh will handle it we say the request has an implicit receiver. T frward the request alng the chain, and t ensure receivers remain implicit, each bject n the chain shares a cmmn interface fr handling requests and fr accessing its successr n the chain.
2 Applicability Use Chain f Respnsibility when mre than ne bject may handle a request, and the handler isn't knwn a priri. The handler shuld be ascertained autmatically. yu want t issue a request t ne f several bjects withut specifying the receiver explicitly. the set f bjects that can handle a request shuld be specified dynamically. Structure
Participants 3 Handler (HelpHandler) defines an interface fr handling requests. (ptinal) implements the successr link. CncreteHandler (PrintButtn, PrintDialg) handles requests it is respnsible fr. can access its successr. Client Cllabratins if the CncreteHandler can handle the request, it des s; therwise it frwards the request t its successr. initiates the request t a CncreteHandler bject n the chain. When a client issues a request, the request prpagates alng the chain until a CncreteHandler bject takes respnsibility fr handling it. Cnsequences 2. Reduced cupling. It can simplify bject intercnnectins. Instead f bjects maintaining references t all candidate receivers, they keep a single reference t their successr. 3. Added flexibility in assigning respnsibilities t bjects. Yu can add r change respnsibilities fr handling a request by adding t r therwise changing the chain at run-time. Yu can cmbine this with subclassing t specialize handlers statically. 4. Receipt isn't guaranteed. Implementatin 1. Implementing the successr chain. a. Define new links (usually in the Handler, but CncreteHandlers culd define them instead). b. Use existing links. Fr example, parent references in a part-whle hierarchy can define a part's successr. 2. Cnnecting successrs (fr new links). The Handler nt nly defines the interface fr the requests but usually maintains the successr as well.
class HelpHandler { HelpHandler(HelpHandler* s) : _successr(s) { virtual vid HandleHelp(); private: HelpHandler* _successr; ; 4 vid HelpHandler::HandleHelp () { if (_successr) { _successr->handlehelp(); 1. Representing requests. a. The request is a hard-cded peratin invcatin. Yu can frward nly the fixed set f requests that the Handler class defines. a. Use a single handler functin that takes a request cde (e.g., an integer cnstant r a string) as parameter. This supprts an pen-ended set f requests. The sender and receiver agree n hw the request shuld be encded. It requires cnditinal statements fr dispatching the request based n its cde. There's n type-safe way t pass parameters, s they must be packed and unpacked manually. Use separate request bjects that bundle request parameters. A Request class can represent requests explicitly, and new kinds f requests can be defined by subclassing. Handlers must knw the kind f request (that is, which Request subclass they're using) t access these parameters. vid Handler::HandleRequest (Request* therequest) { switch (therequest->getkind()) { case Help: // cast argument t apprpriate type HandleHelp((HelpRequest*) therequest); case Print: HandlePrint((PrintRequest*) therequest); default:
Subclasses can extend the dispatch by verriding HandleRequest. The subclass handles nly the requests in which it's interested; ther requests are frwarded t the parent class. In this way, subclasses effectively extend (rather than verride) the HandleRequest peratin. class ExtendedHandler : public Handler { virtual vid HandleRequest(Request* therequest); ; vid ExtendedHandler::HandleRequest (Request* therequest) { switch (therequest->getkind()) { case Preview: // handle the Preview request 5 default: // let Handler handle ther requests Handler::HandleRequest(theRequest); Sample Cde typedef int Tpic; cnst Tpic NO_HELP_TOPIC = -1; class HelpHandler { HelpHandler(HelpHandler* = 0, Tpic = NO_HELP_TOPIC); virtual bl HasHelp(); virtual vid SetHandler(HelpHandler*, Tpic); virtual vid HandleHelp(); private: HelpHandler* _successr; Tpic _tpic; ; HelpHandler::HelpHandler ( HelpHandler* h, Tpic t ) : _successr(h), _tpic(t) { bl HelpHandler::HasHelp () { return _tpic!= NO_HELP_TOPIC; vid HelpHandler::HandleHelp () { if (_successr!= 0) { _successr->handlehelp(); class Widget : public HelpHandler { prtected: Widget(Widget* parent, Tpic t = NO_HELP_TOPIC); private: Widget* _parent; ; Widget::Widget (Widget* w, Tpic t) : HelpHandler(w, t) { _parent = w;
6 class Buttn : public Widget { Buttn(Widget* d, Tpic t = NO_HELP_TOPIC); virtual vid HandleHelp(); // Widget peratins that Buttn verrides... ; Buttn::Buttn (Widget* h, Tpic t) : Widget(h, t) { vid Buttn::HandleHelp () { if (HasHelp()) { // ffer help n the buttn else { HelpHandler::HandleHelp(); class Dialg : public Widget { Dialg(HelpHandler* h, Tpic t = NO_HELP_TOPIC); virtual vid HandleHelp(); ; // Widget peratins that Dialg verrides... Dialg::Dialg (HelpHandler* h, Tpic t) : Widget(0) { SetHandler(h, t); vid Dialg::HandleHelp () { if (HasHelp()) { // ffer help n the dialg else { HelpHandler::HandleHelp(); class Applicatin : public HelpHandler { Applicatin(Tpic t) : HelpHandler(0, t) { ; virtual vid HandleHelp(); // applicatin-specific peratins... vid Applicatin::HandleHelp () { // shw a list f help tpics cnst Tpic PRINT_TOPIC = 1; cnst Tpic PAPER_ORIENTATION_TOPIC = 2; cnst Tpic APPLICATION_TOPIC = 3; Applicatin* applicatin = new Applicatin(APPLICATION_TOPIC); Dialg* dialg = new Dialg(applicatin, PRINT_TOPIC); Buttn* buttn = new Buttn(dialg, PAPER_ORIENTATION_TOPIC); buttn->handlehelp();
7 Knwn Uses Several class libraries use the Chain f Respnsibility pattern t handle user events. MacApp and ET++ : EventHandler TCL library : Bureaucrat NeXT's AppKit : Respnder. In the Unidraw framewrk fr graphical editrs, a cmpnent r a cmpnent view may frward cmmand interpretatin t its parent, which may in turn frward it t its parent, and s n, thereby frming a chain f respnsibility. ET++ uses Chain f Respnsibility t handle graphical update. A graphical bject calls the InvalidateRect peratin whenever it must update a part f its appearance. The default implementatin f InvalidateRect frwards the request t the enclsing cntainer bject. The last bject in the frwarding chain is a Windw instance. Related Patterns Chain f Respnsibility is ften applied in cnjunctin with Cmpsite.