?? pat5a.htm
字號:
<HTML><HEAD><TITLE>Chain of Responsibility</TITLE><SCRIPT>function setFocus() { if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) { return; } else { self.focus(); }}</SCRIPT></HEAD><BODY BGCOLOR = #FFFFFF TEXT = #000000onLoad="setFocus()";><A NAME="top"></A><A NAME="intent"></A><H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Motivation"></A> Intent</H2> <A NAME="auto1000"></A><P>Avoid coupling the sender of a request to its receiver by giving morethan one object a chance to handle the request. Chain the receivingobjects and pass the request along the chain until an objecthandles it.</P><A NAME="motivation"></A><H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Applicability"></A> Motivation</H2> <A NAME="auto1001"></A><P>Consider a context-sensitive help facility for a graphical userinterface. The user can obtain help information on any part of theinterface just by clicking on it. The help that's provided depends onthe part of the interface that's selected and its context; forexample, a button widget in a dialog box might have different helpinformation than a similar button in the main window. If no specifichelp information exists for that part of the interface, thenthe help system should display a more general help message about theimmediate context—the dialog box as a whole, for example.</P><A NAME="auto1002"></A><P>Hence it's natural to organize help information according to itsgenerality—from the most specific to the most general. Furthermore,it's clear that a help request is handled by one of several userinterface objects; which one depends on the context and how specificthe available help is.</P><A NAME="auto1003"></A><P>The problem here is that the object that ultimately <EM>provides</EM> thehelp isn't known explicitly to the object (e.g., the button) that <EM>initiates</EM> the help request. What we need is a way to decouple thebutton that initiates the help request from the objects that mightprovide help information. The Chain of Responsibility pattern defineshow that happens.</P><A NAME="auto1004"></A><P>The idea of this pattern is to decouple senders and receivers bygiving multiple objects a chance to handle a request. The requestgets passed along a chain of objects until one of them handles it.</P><A NAME="223o"></A><P ALIGN=CENTER><IMG SRC="Pictures/chain090.gif"><A NAME="def-implicitreceiver"></A><P>The first object in the chain receives the request and either handlesit or forwards it to the next candidate on the chain, which doeslikewise. The object that made the request has no explicit knowledgeof who will handle it—we say the request has an <STRONG>implicitreceiver</STRONG>.<A NAME="auto1005"></A><P>Let's assume the user clicks for help on a button widget marked"Print." The button is contained in an instance of PrintDialog,which knows the application object it belongs to (see preceding object diagram).The following interaction diagram illustrates how the helprequest gets forwarded along the chain:</P><A NAME="224ci"></A><A NAME="224i"></A><P ALIGN=CENTER><IMG SRC="Pictures/chain091.gif"><A NAME="auto1006"></A><P>In this case, neither aPrintButton nor aPrintDialog handles therequest; it stops at anApplication, which can handle it or ignore it.The client that issued the request has no direct reference to theobject that ultimately fulfills it.</P><A NAME="def-successor"></A><P>To forward the request along the chain, and to ensure receivers remainimplicit, each object on the chain shares a common interface forhandling requests and for accessing its <STRONG>successor</STRONG> on thechain. For example, the help system might define a HelpHandler classwith a corresponding HandleHelp operation. HelpHandler can be theparent class for candidate object classes, or it can be defined as amixin class. Then classes that want to handle help requests can makeHelpHandler a parent:</P><A NAME="224c"></A><P ALIGN=CENTER><IMG SRC="Pictures/chain092.gif"><A NAME="auto1007"></A><P>The Button, Dialog, and Application classes use HelpHandler operationsto handle help requests. HelpHandler's HandleHelp operation forwardsthe request to the successor by default. Subclasses can override thisoperation to provide help under the right circumstances; otherwisethey can use the default implementation to forward the request.</P><A NAME="applicability"></A><H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Structure"></A> Applicability</H2> <A NAME="auto1008"></A><P>Use Chain of Responsibility when</P><UL><A NAME="auto1009"></A><LI>more than one object may handle a request, and the handler isn't known<EM>a priori</EM>. The handler should be ascertained automatically.<A NAME="auto1010"></A><P></P><A NAME="auto1011"></A><LI>you want to issue a request to one of several objects withoutspecifying the receiver explicitly.<A NAME="auto1012"></A><P></P><A NAME="auto1013"></A><LI>the set of objects that can handle a request should be specifieddynamically.</UL><A NAME="structure"></A><H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Participants"></A> Structure</H2> <P ALIGN=CENTER><IMG SRC="Pictures/chain094.gif"><A NAME="auto1014"></A><P>A typical object structure might look like this:<P ALIGN=CENTER><IMG SRC="Pictures/chain089.gif"><A NAME="participants"></A><H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Collaborations"></A> Participants</H2><UL><A NAME="auto1015"></A><LI><B>Handler</B> (HelpHandler)<A NAME="auto1016"></A><P></P><UL> <A NAME="auto1017"></A><LI>defines an interface for handling requests. <A NAME="auto1018"></A><P><!-- extra space --></P> <A NAME="auto1019"></A><LI>(optional) implements the successor link.</UL><A NAME="auto1020"></A><P></P><A NAME="auto1021"></A><LI><B>ConcreteHandler</B> (PrintButton, PrintDialog)<A NAME="auto1022"></A><P></P><UL> <A NAME="auto1023"></A><LI>handles requests it is responsible for. <A NAME="auto1024"></A><P><!-- extra space --></P> <A NAME="auto1025"></A><LI>can access its successor. <A NAME="auto1026"></A><P><!-- extra space --></P> <A NAME="auto1027"></A><LI>if the ConcreteHandler can handle the request, it does so; otherwise it forwards the request to its successor.</UL><A NAME="auto1028"></A><P></P><A NAME="auto1029"></A><LI><B>Client</B><A NAME="auto1030"></A><P></P><UL> <A NAME="auto1031"></A><LI>initiates the request to a ConcreteHandler object on the chain.</UL></UL><A NAME="collaborations"></A><H2><A HREF="#consequences"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Consequences"></A> Collaborations</H2><UL><A NAME="auto1032"></A><LI>When a client issues a request, the request propagates along the chainuntil a ConcreteHandler object takes responsibility for handling it.</UL><A NAME="consequences"></A><H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Implementation"></A> Consequences</H2> <A NAME="auto1033"></A><P>Chain of Responsibility has the following benefits and liabilities:</P><OL><A NAME="auto1034"></A><LI><EM>Reduced coupling.</EM>The pattern frees an object from knowing which other object handles arequest. An object only has to know that a request will be handled"appropriately." Both the receiver and the sender have no explicitknowledge of each other, and an object in the chain doesn't have toknow about the chain's structure.<A NAME="auto1035"></A><P>As a result, Chain of Responsibility can simplify objectinterconnections. Instead of objects maintaining references to allcandidate receivers, they keep a single reference to their successor.</P></LI><A NAME="auto1036"></A><P></P><A NAME="auto1037"></A><LI><EM>Added flexibility in assigning responsibilities to objects.</EM>Chain of Responsibility gives you added flexibility in distributingresponsibilities among objects. You can add or changeresponsibilities for handling a request by adding to or otherwisechanging the chain at run-time. You can combine this with subclassingto specialize handlers statically.</LI><A NAME="auto1038"></A><P></P><A NAME="guarantee-receipt"></A><LI><EM>Receipt isn't guaranteed.</EM>Since a request has no explicit receiver, there's no <EM>guarantee</EM>it'll be handled—the request can fall off the end of the chainwithout ever being handled. A request can also go unhandled when thechain is not configured properly.</LI></OL><A NAME="implementation"></A><H2><A HREF="#samplecode"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Sample Code"></A> Implementation</H2> <A NAME="auto1039"></A><P>Here are implementation issues to consider in Chain of Responsibility:</P><OL><A NAME="auto1040"></A><LI><EM>Implementing the successor chain.</EM>There are two possible ways to implement the successor chain:</LI><A NAME="auto1041"></A><P></P><OL><LI TYPE=a>Define new links (usually in the Handler, but ConcreteHandlerscould define them instead).</LI><A NAME="auto1042"></A><P></P><LI TYPE=a>Use existing links.</LI></OL><A NAME="auto1043"></A><P>Our examples so far define new links, but often you can use existingobject references to form the successor chain. For example, parentreferences in a part-whole hierarchy can define a part's successor. Awidget structure might already have such links.<A HREF="pat4cfs.htm" TARGET="_mainDisplayFrame">Composite (163)</A> discusses parent references in moredetail.</P><A NAME="auto1044"></A><P>Using existing links works well when the links support the chain youneed. It saves you from defining links explicitly, and it savesspace. But if the structure doesn't reflect the chain ofresponsibility your application requires, then you'll have to defineredundant links.</P></LI><A NAME="auto1045"></A><P></P><A NAME="succ-connect"></A><LI><EM>Connecting successors.</EM>If there are no preexisting references for defining a chain, then you'llhave to introduce them yourself. In that case, the Handler not onlydefines the interface for the requests but usually maintains thesuccessor as well. That lets the handler provide a defaultimplementation of HandleRequest that forwards the request to thesuccessor (if any). If a ConcreteHandler subclass isn't interestedin the request, it doesn't have to override the forwarding operation,since its default implementation forwards unconditionally.<A NAME="auto1046"></A><P>Here's a HelpHandler base class that maintains a successor link:</P><A NAME="auto1047"></A><PRE> class HelpHandler { public: HelpHandler(HelpHandler* s) : _successor(s) { } virtual void HandleHelp(); private: HelpHandler* _successor; }; void HelpHandler::HandleHelp () { if (_successor) { _successor->HandleHelp(); } }</PRE><A NAME="auto1048"></A><P></P><A NAME="represent-request"></A><LI><EM>Representing requests.</EM>Different options are available for representing requests. In thesimplest form, the request is a hard-coded operation invocation, as inthe case of HandleHelp. This is convenient and safe, but you can
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -