Memento, Observer, and State

Memento, Observer, and State

CHAPTER 8 Memento, Observer, and State Objectives The objectives of this chapter are to identify the following: • Introduce the memento, state, and observer patterns. • Create basic UML diagrams for these design patterns. Software Development Methods 1 Memento, Observer, and State Memento Pattern Use the Memento pattern when: • A snapshot of some portion of an object’s internal state must be saved so that it can be restored to that state later, and • A direct interface to obtaining the state would expose implementation details and break the object’s encapsulation. Mementos have three (3) participants: • A Memento which stores the internal state of the originator object. The memento may store whatever parts of the originator’s state the originator deems necessary. The memento is also responsible for preventing anyone but the originator manipulate the actual contents of the memento. • An Originator which creates the memento that stores the snapshot of its cur- rent state. The originator also uses the memento to restore its internal state if necessary. • A Caretaker which is responsible for the memento’s safekeeping. The care- taker never examines or manipulates the contents of the memento. The results we gain from implementing a Memento pattern are: • Preserving encapsulation boundaries. Mementos prevent data that is techni- cally private to the originator from being made public once its is stored. This pattern is still able to hide the implementation details of the originator. • It simplifies the originator. By allowing a client to manage the state it needs, we can remove the burden of storage management from the originator. • Mementos can be resource intensive. If the internal state of the originator is complex, the time and memory needed to construct a memento might be sig- nificant. Also consider if a heavyweight memento is garbage collected by a lightweight client, the storage cost might be significant • Defining the correct interfaces may be difficult. For the memento to behave properly, it must only allow the originator to manipulate its internal state. These kinds of restrictions can be difficult if the language does not support RTTI. To illustrate this design pattern, consider the following undo example from the graphical application described by your text: The Graphic class is simply used as a base class for all possible drawing objects. We don’t actually use it as anything more than a placeholder in this sam- ple application. 2 Software Development Methods Memento, Observer, and State class Graphic { ... }; The MoveCommand class stores information about the moves that have taken place within the drawing. This is what allows us to undo commands later on dur- ing program execution. Specifically, each MoveCommand will store the current state of the ConstraintSolver class detailed below. class MoveCommand { private: ConstraintSolverMemento * _state; Point _delta; Graphic * _target; public: MoveCommand(Graphic *target, const Point & delta); void Execute(void); void Unexecute(void); }; The Java equivalent might appear as: public class MoveCommand { private ConstraintSolverMemento _state; private Point _delta; private Graphic _target; public MoveCommand(Graphic target, Point delta) {...} public void Execute() { ... } public void Unexecute() { ... } } Now we implement the ConstraintSolver class. This class is responsible for recording the various connections as they’re made and for generating the mathematical equations that describe them. When the diagram is modified, these equations are re-solved and the results used to re-draw the connections so that they continue to refer to the correct graphics. Software Development Methods 3 Memento, Observer, and State class ConstraintSolver { private: // non-trivial stuff public: static ConstraintSolver * Instance(void); void Solve(void); void AddConstraint(Graphic *s, Graphic *e); void RemoveConstraint(Graphic *s, Graphic *e); ConstraintSolverMemento * CreateMemento(void); void SetMemento(ConstraintSolverMemento *); }; The Java equivalent might appear as: public class ConstraintSolver { // non-trivial private stuff public static ConstraintSolver Instance() { ... } public void Solve(void) { ... } public void AddConstraint(Graphic s, Graphic e) {...} public void RemoveConstraint(Graphic s, Graphic e) { ... } public ConstraintSolverMemento CreateMemento() {...} public void SetMemento(ConstraintSolverMemento m) { ... } }; Now we need to define the ConstraintSolverMemento class. This class is responsible for packaging up whatever part of the ConstraintSolver’s state the ConstraintSolver deems necessary: class ConstraintSolverMemento { private: // private constraint solver state data friend class ConstraintSolver; ConstraintSolverMemento(); public: virtual ~ConstraintSolverMemento(); }; The corresponding Java code is a bit more complex. Java does not support friend functions so to implement this pattern we might need to use an inner class. An inner class is simply one class defined within another. Thus we might change the definition of the ConstraintSolver class to include that of the Con- straintSolverMemento class: 4 Software Development Methods Memento, Observer, and State public class ConstraintSolver { public class ConstraintSolverMemento { // private constraint solver state data private ConstraintSolverMemento(); }; // non-trivial private stuff public static ConstraintSolver Instance() { ... } public void Solve(void) { ... } public void AddConstraint(Graphic s, Graphic e) {...} public void RemoveConstraint(Graphic s, Graphic e) { ... } public ConstraintSolverMemento CreateMemento() {...} public void SetMemento(ConstraintSolverMemento m) { ... } }; To see how we can use this class, consider the Execute() and Unexecute() methods of the MoveCommand class: void MoveCommand::Execute(void) { ConstraintSolver * solver = ConstraintSolver::Instance(); _state = solver->CreateMemento(); _target->Move(_delta); solver->Solve(); } void MoveCommand::Unexecute(void) { ConstraintSolver * solver = ConstraintSolver::Instance(); _target->Move(-_delta); solver->SetMemento(_state); solver->Solve(); } The Java equivalent might appear as: void Execute() { ConstraintSolver solver = ConstraintSolver.Instance(); _state = solver.CreateMemento(); _target.Move(_delta); solver.Solve(); } Software Development Methods 5 Memento, Observer, and State void Unexecute() { ConstraintSolver solver = ConstraintSolver.Instance(); _target.Move(-_delta); solver.SetMemento(_state); solver.Solve(); } Observer Pattern Use the Observer pattern when: • An abstraction has two interdependent abstractions. By encapsulating these aspects in separate objects, we gain the ability to vary and reuse them inde- pendently. • A change to one object requires changing others. You don’t know (or want to know) how many objects need to be changed. • An object should be able to notify other objects without making assumptions about who those objects are; we don’t want these objects tightly coupled by forcing one to know about the type of the other. Observers have four (4) participants: • A Subject which knows its observers. Ultimately it will be objects descended from this abstract class that broadcast the fact that they have changed. Any number of observers may observe a given subject. The subject provides an interface used to attach and detach observers. • An Observer which provides an interface to be used by the subject when a notification needs to be made. • A Concrete Subject which stores state data of interest to concrete observers. When this class changes state it will notify each of its observers via a method in their interface. • A Concrete Observer which maintains a reference to a concrete subject object. These objects will store state that needs to remain consistent with the concrete subject’s. This class will be notified of changes to its subject via an observer updating interface. The results we gain from implementing an Observer pattern are: • Abstract coupling between subject and observer. Since subjects an observer’s communicate with one another only via a simple interface, it is possible to vary them significantly and ensure that they’re not dependent upon one another’s internal state. 6 Software Development Methods Memento, Observer, and State • Support for broadcast communication. When a subject changes, it simply notifies all interested observers. Since observers may be dynamically added and removed during run-time this provides great flexibility. • Unexpected updates. This can be a serious problem. A minor change in the subject might result in significant alterations to the observer. Usually this kind of subject-observer notification also doesn’t specify what changed which means that a great deal of work may be done for no good reason. To fix this problem requires inventing an application-specific protocol to coordinate and optimize these changes. To illustrate this design pattern, consider the following example from the text which features a simple clock. We first define the Observer class: class Observer { protected: Observer(); public: virtual ~Observer(); virtual void Update(Subject * changed) = 0; }; In Java we might code this class as: public class Observer { protected Observer(); abstract void Update(Subject * changed); }; Now we define the abstract Subject class: class Subject { private: List<Observer *> * _observers; protected: Subject(); public: virtual ~Observer(); virtual void Attach(Observer *); virtual void Detach(Observer *); virtual void Notify(void); }; In Java we might code this class as: Software Development

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    16 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us