⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pat5h.htm

📁 Design Pattern 设计模式
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<P></P><A NAME="auto1049"></A><P>The key difference between table-driven state machines and the Statepattern can be summed up like this: The State pattern modelsstate-specific behavior, whereas the table-driven approach focuses ondefining state transitions.</P></LI><A NAME="auto1050"></A><P></P><A NAME="auto1051"></A><LI><EM>Creating and destroying State objects.</EM>A common implementation trade-off worth considering is whether(1) to create State objects only when they are needed and destroy themthereafter versus (2) creating them ahead of time and neverdestroying them.<A NAME="auto1052"></A><P>The first choice is preferable when the states that will be enteredaren't known at run-time, <EM>and</EM> contexts change stateinfrequently.  This approach avoids creating objects that won't beused, which is important if the State objects store a lot ofinformation.  The second approach is better when state changes occurrapidly, in which case you want to avoid destroying states, becausethey may be needed again shortly.  Instantiation costs are paid onceup-front, and there are no destruction costs at all.  This approachmight be inconvenient, though, because the Context must keepreferences to all states that might be entered.</P></LI><A NAME="auto1053"></A><P></P><A NAME="dynamicinherit"></A><A NAME="self"></A><LI><EM>Using dynamic inheritance.</EM>Changing the behavior for a particular request could be accomplishedby changing the object's class at run-time, but this is not possiblein most object-oriented programming languages.  Exceptions includeSelf [<A HREF="bibfs.htm#ungar_self" TARGET="_mainDisplayFrame">US87</A>] and other delegation-based languages thatprovide such a mechanism and hence support the State pattern directly.Objects in Self can delegate operations to other objects to achieve aform of dynamic inheritance.  Changing the delegation target atrun-time effectively changes the inheritance structure.  Thismechanism lets objects change their behavior and amounts to changingtheir class.</LI></OL><A NAME="samplecode"><A><H2><A HREF="#knownuses"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Known Uses"></A> Sample Code</H2> <A NAME="auto1054"></A><P>The following example gives the C++ code for the TCP connectionexample described in the Motivation section.  This example is asimplified version of the TCP protocol; it doesn't describe thecomplete protocol or all the states of TCPconnections.<A NAME="fn8"></A><SUP><A HREF="#footnote8">8</A></SUP></P><A NAME="auto1055"></A><P>First, we define the class <CODE>TCPConnection</CODE>, which provides aninterface for transmitting data and handles requests to change state.</P><A NAME="auto1056"></A><PRE>    class TCPOctetStream;    class TCPState;        class TCPConnection {    public:        TCPConnection();            void ActiveOpen();        void PassiveOpen();        void Close();            void Send();        void Acknowledge();        void Synchronize();            void ProcessOctet(TCPOctetStream*);    private:        friend class TCPState;        void ChangeState(TCPState*);    private:        TCPState* _state;    };</PRE><A NAME="tcpstate2"></A><P><CODE>TCPConnection</CODE> keeps an instance of the <CODE>TCPState</CODE>class in the <CODE>_state</CODE> member variable.  The class<CODE>TCPState</CODE> duplicates the state-changing interface of<CODE>TCPConnection</CODE>. Each <CODE>TCPState</CODE> operation takes a<CODE>TCPConnection</CODE> instance as a parameter, letting<CODE>TCPState</CODE> access data from <CODE>TCPConnection</CODE> andchange the connection's state.</P><A NAME="auto1057"></A><PRE>    class TCPState {    public:        virtual void Transmit(TCPConnection*, TCPOctetStream*);        virtual void ActiveOpen(TCPConnection*);        virtual void PassiveOpen(TCPConnection*);        virtual void Close(TCPConnection*);        virtual void Synchronize(TCPConnection*);        virtual void Acknowledge(TCPConnection*);        virtual void Send(TCPConnection*);    protected:        void ChangeState(TCPConnection*, TCPState*);    };</PRE><A NAME="auto1058"></A><P><CODE>TCPConnection</CODE> delegates all state-specific requests to its<CODE>TCPState</CODE> instance <CODE>_state</CODE>.<CODE>TCPConnection</CODE> also provides an operation for changing thisvariable to a new <CODE>TCPState</CODE>.  The constructor for<CODE>TCPConnection</CODE> initializes the object to the<CODE>TCPClosed</CODE> state (defined later).</P><A NAME="auto1059"></A><PRE>    TCPConnection::TCPConnection () {        _state = TCPClosed::Instance();    }        void TCPConnection::ChangeState (TCPState* s) {        _state = s;    }        void TCPConnection::ActiveOpen () {        _state->ActiveOpen(this);    }        void TCPConnection::PassiveOpen () {        _state->PassiveOpen(this);    }        void TCPConnection::Close () {        _state->Close(this);    }        void TCPConnection::Acknowledge () {        _state->Acknowledge(this);    }        void TCPConnection::Synchronize () {        _state->Synchronize(this);    }</PRE><A NAME="auto1060"></A><P><CODE>TCPState</CODE> implements default behavior for all requestsdelegated to it.  It can also change the state of a<CODE>TCPConnection</CODE> with the <CODE>ChangeState</CODE> operation.<CODE>TCPState</CODE> is declared a friend of <CODE>TCPConnection</CODE> togive it privileged access to this operation.</P><A NAME="auto1061"></A><PRE>    void TCPState::Transmit (TCPConnection*, TCPOctetStream*) { }    void TCPState::ActiveOpen (TCPConnection*) { }    void TCPState::PassiveOpen (TCPConnection*) { }    void TCPState::Close (TCPConnection*) { }    void TCPState::Synchronize (TCPConnection*) { }        void TCPState::ChangeState (TCPConnection* t, TCPState* s) {        t->ChangeState(s);    }</PRE><A NAME="auto1062"></A><P>Subclasses of <CODE>TCPState</CODE> implement state-specific behavior. ATCP connection can be in many states: Established, Listening, Closed,etc., and there's a subclass of <CODE>TCPState</CODE> for each state.We'll discuss three subclasses in detail: <CODE>TCPEstablished</CODE>,<CODE>TCPListen</CODE>, and <CODE>TCPClosed</CODE>.</P><A NAME="auto1063"></A><PRE>    class TCPEstablished : public TCPState {    public:        static TCPState* Instance();            virtual void Transmit(TCPConnection*, TCPOctetStream*);        virtual void Close(TCPConnection*);    };        class TCPListen : public TCPState {    public:        static TCPState* Instance();            virtual void Send(TCPConnection*);        // ...    };        class TCPClosed : public TCPState {    public:        static TCPState* Instance();            virtual void ActiveOpen(TCPConnection*);        virtual void PassiveOpen(TCPConnection*);        // ...    };</PRE><A NAME="auto1065"></A><P><CODE>TCPState</CODE> subclasses maintain no local state, sothey can be shared, and only one instance of each is required.  Theunique instance of each <CODE>TCPState</CODE> subclass is obtained by thestatic <CODE>Instance</CODE>operation.<A NAME="fn9"></A><SUP><A HREF="#footnote9">9</A></SUP></P><A NAME="auto1066"></A><P>Each <CODE>TCPState</CODE> subclass implements state-specific behaviorfor valid requests in the state:</P><A NAME="auto1067"></A><PRE>    void TCPClosed::ActiveOpen (TCPConnection* t) {        // send SYN, receive SYN, ACK, etc.            ChangeState(t, TCPEstablished::Instance());    }        void TCPClosed::PassiveOpen (TCPConnection* t) {        ChangeState(t, TCPListen::Instance());    }        void TCPEstablished::Close (TCPConnection* t) {        // send FIN, receive ACK of FIN            ChangeState(t, TCPListen::Instance());    }        void TCPEstablished::Transmit (        TCPConnection* t, TCPOctetStream* o    ) {        t->ProcessOctet(o);    }        void TCPListen::Send (TCPConnection* t) {        // send SYN, receive SYN, ACK, etc.            ChangeState(t, TCPEstablished::Instance());    }</PRE><A NAME="auto1068"></A><P>After performing state-specific work, these operations call the<CODE>ChangeState</CODE> operation to change the state ofthe <CODE>TCPConnection</CODE>.  <CODE>TCPConnection</CODE> itself doesn'tknow a thing about the TCP connection protocol; it's the<CODE>TCPState</CODE> subclasses that define each state transitionand action in TCP.</P><A NAME="knownuses"><A><H2><A HREF="#relatedpatterns"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Related Patterns"></A> Known Uses</H2> <A NAME="auto1069"></A><P>Johnson and Zweig [<A HREF="bibfs.htm#johnson-zweig_delegation" TARGET="_mainDisplayFrame">JZ91</A>] characterize theState pattern and its application to TCP connection protocols.</P><A NAME="auto1070"></A><P>Most popular interactive drawing programs provide "tools" forperforming operations by direct manipulation.  For example, aline-drawing tool lets a user click and drag to create a new line.  Aselection tool lets the user select shapes.  There's usually a paletteof such tools to choose from.  The user thinks of this activity aspicking up a tool and wielding it, but in reality the editor'sbehavior changes with the current tool: When a drawing tool is activewe create shapes; when the selection tool is active we select shapes;and so forth.  We can use the State pattern to change the editor'sbehavior depending on the current tool.</P><A NAME="tool-class"></A><P>We can define an abstract Tool class from which to define subclassesthat implement tool-specific behavior.  The drawing editor maintains acurrent Tool object and delegates requests to it.  It replaces thisobject when the user chooses a new tool, causing the behavior of thedrawing editor to change accordingly.  </P><A NAME="unidraw-use-state"></A><P>This technique is used in both the HotDraw [<A HREF="bibfs.htm#hotdraw" TARGET="_mainDisplayFrame">Joh92</A>] and Unidraw [<A HREF="bibfs.htm#unidraw_framework" TARGET="_mainDisplayFrame">VL90</A>] drawing editor frameworks. It allows clients to define new kinds of tools easily. In HotDraw, the DrawingController class forwards the requests to the current Tool object. In Unidraw, the corresponding classes are Viewer and Tool. The following class diagram sketches the Tool and DrawingController interfaces:</P><A NAME="tool-313c"></A><P ALIGN=CENTER><IMG SRC="Pictures/state012.gif"></P><A NAME="envelope-letter"></A><P>Coplien's Envelope-Letter idiom [<A HREF="bibfs.htm#coplien_idioms" TARGET="_mainDisplayFrame">Cop92</A>] is related toState.  Envelope-Letter is a technique for changing an object's class atrun-time. The State pattern is more specific, focusing on how to dealwith an object whose behavior depends on its state.</P><A NAME="relatedpatterns"></A><H2><A HREF="#last"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: navigation"></A> Related Patterns</H2> <A NAME="auto1072"></A><P>The <A HREF="pat4ffs.htm" TARGET="_mainDisplayFrame">Flyweight (195)</A>pattern explains when and how State objects can be shared.</P><A NAME="auto1073"></A><P>State objects are often<A HREF="pat3efs.htm" TARGET="_mainDisplayFrame">Singletons (127)</A>.</P><A NAME="last"></A><P><A HREF="#intent"><IMG SRC="gifsb/up3.gif" BORDER=0></A><BR><A HREF="pat5ifs.htm" TARGET="_mainDisplayFrame"><IMG SRC="gifsb/rightar3.gif"        ALIGN=TOP BORDER=0></A> <A HREF="pat5ifs.htm"        TARGET="_mainDisplayFrame">Strategy</A><BR><A HREF="pat5gfs.htm" TARGET="_mainDisplayFrame"><IMG SRC="gifsb/leftarr3.gif"        ALIGN=TOP BORDER=0></A> <A HREF="pat5gfs.htm"        TARGET="_mainDisplayFrame">Observer</A></P><HR><A NAME="footnote8"></A><SUP>8</SUP>This example is based on the TCP connection protocoldescribed by Lynch andRose [<A HREF="bibfs.htm#lynch-rose_internet" TARGET="_mainDisplayFrame">LR93</A>].</P><A NAME="footnote9"></A><SUP>9</SUP>This makes each <CODE>TCPState</CODE> subclass a Singleton (see<A HREF="pat3efs.htm" TARGET="_mainDisplayFrame">Singleton (127)</A>).</P> </BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -