?? pat5f.htm
字號:
<HTML><HEAD><TITLE>Memento</TITLE><SCRIPT>function setFocus() { if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) { return; } else { self.focus(); }}</SCRIPT></HEAD><BODY BGCOLOR = #FFFFFFonLoad="setFocus()";><A NAME="top"></A><A NAME="Memento"></A><A NAME="intent"></A><H2><A HREF="#alsoknownas"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Also Known As"></A> Intent</H2> <A NAME="auto1000"></A><P>Without violating encapsulation, capture and externalize an object'sinternal state so that the object can be restored to this state later.</P><A NAME="alsoknownas"><A><H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Motivation"></A> Also Known As</H2> <A NAME="auto1001"></A><P>Token</P><A NAME="motivation"></A><H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Applicability"></A> Motivation</H2> <A NAME="auto1002"></A><P>Sometimes it's necessary to record the internal state of an object.This is required when implementing checkpoints and undo mechanismsthat let users back out of tentative operations or recover fromerrors. You must save state information somewhere so that you canrestore objects to their previous states. But objects normallyencapsulate some or all of their state, making it inaccessible toother objects and impossible to save externally. Exposing this statewould violate encapsulation, which can compromise the application'sreliability and extensibility.</P><A NAME="auto1003"></A><P>Consider for example a graphical editor that supports connectivitybetween objects. A user can connect two rectangles with a line, andthe rectangles stay connected when the user moves either of them. Theeditor ensures that the line stretches to maintain the connection.</P><P ALIGN=CENTER><IMG SRC="Pictures/memen029.gif"></P><A NAME="auto1004"></A><P>A well-known way to maintain connectivity relationships betweenobjects is with a constraint-solving system. We can encapsulate thisfunctionality in a <STRONG>ConstraintSolver</STRONG> object.ConstraintSolver records connections as they are made and generatesmathematical equations that describe them. It solves these equationswhenever the user makes a connection or otherwise modifies thediagram. ConstraintSolver uses the results of its calculations torearrange the graphics so that they maintain the proper connections.</P><A NAME="supp-undo"></A><P>Supporting undo in this application isn't as easy as it may seem. Anobvious way to undo a move operation is to store the original distancemoved and move the object back an equivalent distance. However, thisdoes not guarantee all objects will appear where they did before.Suppose there is some slack in the connection. In that case, simplymoving the rectangle back to its original location won't necessarilyachieve the desired effect.</P><P ALIGN=CENTER><IMG SRC="Pictures/memen028.gif"></P><A NAME="auto1005"></A><P>In general, the ConstraintSolver's public interface might beinsufficient to allow precise reversal of its effects on otherobjects. The undo mechanism must work more closely withConstraintSolver to reestablish previous state, but we should alsoavoid exposing the ConstraintSolver's internals to the undo mechanism.</P><A NAME="orig-def"></A><P>We can solve this problem with the Memento pattern. A<STRONG>memento</STRONG> is an object that stores a snapshot of theinternal state of another object—the memento's<STRONG>originator</STRONG>. The undo mechanism will request a mementofrom the originator when it needs to checkpoint the originator'sstate. The originator initializes the memento with information thatcharacterizes its current state. Only the originator can store andretrieve information from the memento—the memento is "opaque" toother objects.</P><A NAME="auto1006"></A><P>In the graphical editor example just discussed, the ConstraintSolver can actas an originator. The following sequence of events characterizes theundo process:</P><OL><A NAME="auto1007"></A><LI>The editor requests a memento from the ConstraintSolver as aside-effect of the move operation.</LI><A NAME="auto1008"></A><P></P><A NAME="solverstate"></A><LI>The ConstraintSolver creates and returns a memento, an instance of aclass SolverState in this case. A SolverState memento contains datastructures that describe the current state of the ConstraintSolver'sinternal equations and variables.</LI><A NAME="auto1009"></A><P></P><A NAME="auto1010"></A><LI>Later when the user undoes the move operation, the editor gives theSolverState back to the ConstraintSolver.</LI><A NAME="auto1011"></A><P></P><A NAME="auto1012"></A><LI>Based on the information in the SolverState, the ConstraintSolverchanges its internal structures to return its equations and variablesto their exact previous state.</LI></OL><A NAME="auto1013"></A><P>This arrangement lets the ConstraintSolver entrust other objects withthe information it needs to revert to a previous state withoutexposing its internal structure and representations.</P><A NAME="applicability"></A><H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Structure"></A> Applicability</H2> <A NAME="auto1014"></A><P>Use the Memento pattern when</P><UL><A NAME="auto1015"></A><LI>a snapshot of (some portion of) an object's state must be saved sothat it can be restored to that state later, <EM>and</EM></LI><A NAME="auto1016"></A><P></P><A NAME="auto1017"></A><LI>a direct interface to obtaining the state would exposeimplementation details and break the object's encapsulation.</LI></UL><A NAME="structure"></A><H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Participants"></A> Structure</H2> <A NAME="orig-285c"></A><P ALIGN=CENTER><IMG SRC="Pictures/memento.gif"></P><A NAME="participants"></A><H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Collaborations"></A> Participants</H2><UL><A NAME="auto1018"></A><LI><B>Memento</B> (SolverState)</LI><A NAME="auto1019"></A><P></P> <UL> <A NAME="auto1020"></A><LI>stores internal state of the Originator object. The memento may store as much or as little of the originator's internal state as necessary at its originator's discretion.</LI> <A NAME="auto1021"></A><P><!-- extra space --></P> <A NAME="auto1022"></A><LI>protects against access by objects other than the originator. Mementos have effectively two interfaces. Caretaker sees a <EM>narrow</EM> interface to the Memento—it can only pass the memento to other objects. Originator, in contrast, sees a <EM>wide</EM> interface, one that lets it access all the data necessary to restore itself to its previous state. Ideally, only the originator that produced the memento would be permitted to access the memento's internal state.</LI> </UL><A NAME="auto1023"></A><P></P><A NAME="auto1024"></A><LI><B>Originator</B> (ConstraintSolver)</LI><A NAME="auto1025"></A><P></P> <UL> <A NAME="auto1026"></A><LI>creates a memento containing a snapshot of its current internal state.</LI> <A NAME="auto1027"></A><P><!-- extra space --></P> <A NAME="auto1028"></A><LI>uses the memento to restore its internal state.</LI> </UL><A NAME="auto1029"></A><P></P><A NAME="auto1030"></A><LI><B>Caretaker</B> (undo mechanism)<A NAME="auto1031"></A><P></P> <UL> <A NAME="auto1032"></A><LI>is responsible for the memento's safekeeping.</LI> <A NAME="auto1033"></A><P><!-- extra space --></P> <A NAME="auto1034"></A><LI>never operates on or examines the contents of a memento.</LI> </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="auto1035"></A><LI>A caretaker requests a memento from an originator, holds it for atime, and passes it back to the originator, as the followinginteraction diagram illustrates:<A NAME="orig-286i"></A><P ALIGN=CENTER><IMG SRC="Pictures/memen027.gif"></P><A NAME="auto1036"></A><P>Sometimes the caretaker won't pass the memento back to the originator,because the originator might never need to revert to an earlier state.</P></LI><A NAME="auto1037"></A><P></P><A NAME="auto1038"></A><LI>Mementos are passive. Only the originator that created a memento willassign or retrieve its state.</LI></UL><A NAME="consequences"></A><H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Implementation"></A> Consequences</H2> <A NAME="auto1039"></A><P>The Memento pattern has several consequences:</P><OL><A NAME="presrvencap"></A><LI><EM>Preserving encapsulation boundaries.</EM>Memento avoids exposing information that only an originator shouldmanage but that must be stored nevertheless outside the originator.The pattern shields other objects from potentially complex Originatorinternals, thereby preserving encapsulation boundaries.</LI><A NAME="auto1040"></A><P></P><A NAME="auto1041"></A><LI><EM>It simplifies Originator.</EM>In other encapsulation-preserving designs, Originator keeps theversions of internal state that clients have requested. That puts allthe storage management burden on Originator. Having clientsmanage the state they ask for simplifies Originator and keepsclients from having to notify originators when they're done.</LI><A NAME="auto1042"></A><P></P><A NAME="auto1043"></A><LI><EM>Using mementos might be expensive.</EM>Mementos might incur considerable overhead if Originator must copylarge amounts of information to store in the memento or if clientscreate and return mementos to the originator often enough. Unlessencapsulating and restoring Originator state is cheap, the patternmight not be appropriate. See the discussion of incrementality in theImplementation section.</LI><A NAME="auto1044"></A><P></P><A NAME="auto1045"></A><LI><EM>Defining narrow and wide interfaces.</EM>It may be difficult in some languages to ensure that only theoriginator can access the memento's state.</LI><A NAME="auto1046"></A><P></P><A NAME="auto1047"></A><LI><EM>Hidden costs in caring for mementos.</EM>A caretaker is responsible for deleting the mementos it cares for.However, the caretaker has no idea how much state is in the memento.Hence an otherwise lightweight caretaker might incur large storagecosts when it stores mementos.</LI>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -