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 .

Software Development Methods 1 Memento, Observer, and State

Memento Pattern Use the 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 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 * _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 Methods 7 Memento, Observer, and State

public class Subject { private Vector _observers; protected Subject() { ... }; public void Attach(Observer * obs) { ... } public void Detach(Observer * obs) { ... } public void Notify() { ... } };

We define the methods within the Subject class as:

void Subject::Attach(Observer * obs) { _observers->Append(o); }

void Subject::Detach(Observer * obs) { _observers->Remove(o); }

void Subject::Notify(void) { ListIterator i(_observers);

for (i.First(); !i.IsDone(); i.Next()) { i.CurrentItem()->Update(this); } }

In Java this code might appear as:

void Attach(Observer obs) { _observers.Add(o); }

void Detach(Observer obs) { _observers.Remove(o); }

void Notify() { Enumeration e = _observers.elements();

while (e.hasMoreElements()) { e.nextElement().Update(this); } }

8 Software Development Methods Memento, Observer, and State

Now that we have our abstract Subject and Observer classes, we can build a simple notification scheme involving clocks. The ClockTimer class is a con- crete subject that maintains the time of day. It notifies its observers every second:

class ClockTimer : public Subject { public: ClockTimer(); virtual int GetHour(void); virtual int GetMinute(void); virtual int GetSecond(void); void Tick(void); };

The corresponding Java class would appear as:

public class ClockTimer extends Subject { public ClockTimer() { ... } public int GetHour() { ... } public int GetMinute() { ... } public int GetSecond() { ... } public void Tick() { ... } };

The Tick() method is responsible for updating the ClockTimer’s internal state. It is triggered by an internal clock and it then calls Notify() to make all of the observers aware of the time change:

void ClockTimer::Tick() { // update internal state Notify(); }

The Java code would appear as:

public void Tick() { // update internal state Notify(); }

We now need to define an observer for our subject. We will introduce the Digi- talClock class:

Software Development Methods 9 Memento, Observer, and State

class DigitalClock : public Observer { private: ClockTimer * _subject; public: DigitalClock(ClockTimer *); virtual ~DigitalClock(); virtual void Update(Subject *); virtual void Draw(void); };

The Java code might appear as:

public class DigitalClock extends Observer { private ClockTimer _subject; public DigitalClock(ClockTimer ct) { ... } public void Update(Subject s) { ... } public void Draw() { ... } };

We can now implement the methods:

DigitalClock::DigitalClock(ClockTimer * ct) { _subject = ct; _subject->Attach(this); }

DigitalClock::~DigitalClock() { _subject->Detach(this); }

In Java things are a bit more interesting simply because we don’t have a destruc- tor since we don’t control when garbage collection occurs. The best we can do is code a finalize() method that will execute when the object is finally garbage collected.

public DigitalClock(ClockTimer ct) { _subject = ct; _subject.Attach(this); }

void finalize() throws Throwable { _subject.Detach(this); }

We can now look to the Update() method. This method checks to ensure that the notifying subject is the clock’s subject and then re-draws the clock face:

10 Software Development Methods Memento, Observer, and State

void DigitalClock::Update(Subject * subject) { if (_subject == subject) { Draw(); } }

In Java this code would be written almost identically:

public void Update(Subject subject) { if (_subject == subject) { Draw(); } }

To code the Draw() method, we simply regenerate all of the internal data for the DigitalClock class, possibly drawing upon the data in the subject to do so:

void DigitalClock::Draw(void) { // get new values from the subject int hour = _subject->GetHour(); int minute = _subject->GetMinute(); int second = _subject->GetSecond(); // draw the clock }

The Java definition would appear as:

public void Draw() { // get new values from the subject int hour = _subject.GetHour(); int minute = _subject.GetMinute(); int second = _subject.GetSecond(); // draw the clock }

To actually use these classes you might have the following code in main:

ClockTimer * timer = new ClockTimer(); DigitalClock * clock = new DigitalClock(timer);

Thus whenever the timer ticks, the clock will be updated.

Software Development Methods 11 Memento, Observer, and State

State Pattern One of the UML diagrams you’ve seen in this class is the stateflow diagram which shows the various states of an object as well as the transitions that are allowed from one state to the next. Sometimes our applications conform to these stateflows very closely and we’d like some of the functions to behave differently based on the application’s current state. This is the essence of the State pattern.

Use the State pattern when: • An object’s behavior depends on its state and it must change that behavior at run-time based on that state, or • Operations have multipart conditional statements that depend on the object’s state. The state pattern will put each branch of the condition into a different class which allows you to treat the object’s state as an object itself.

States have three (3) participants: • A Context which defines an interface to clients. This context maintains an instance of a Concrete State subclass that defines the current state. • A State which defines an interface for encapsulating the behavior associated with a particular state of the Context. Essentially this means that the State defines an interface which is redefined by each of its subclasses. When the method is invoked by the Context, the appropriate method for the current state will be executed. • Concrete State subclasses, each of which implements the appropriate behav- ior for the State interface.

The results we gain from implementing a State pattern are: • Localize state-specific behavior and partition behavior for different states. By placing all information about a given state into its own object, new states and transitions can be added fairly quickly. This can take the place of long annoying conditional or switch statements within the Context code. However, the cost is that we introduce additional classes and scatter the state code throughout various subclasses. It can be hard to form a coherent picture of what’s going on for any given state. • State transitions become explicit. By introducing separate objects for each state, the transitions become more explicit. This is as opposed to simply assigning a value to an internal data member. • State objects can be shared. If the state objects have no instance variables, then multiple contexts could share a single state object. Check out the Fly- weight pattern for another approach to dealing with this situation.

12 Software Development Methods Memento, Observer, and State

For our sample application we look at a TCP/IP connection. Connections may be in numerous states and the behavior and possible transitions change depending on our state at the time the transition is encountered. In some cases we’ll do actual work, in others we ignore the transition because it isn’t valid.

We first begin by defining the TCPConnection class. This class is responsible for transmitting data and for changing the state of a given TCPConnection object:

class TCPConnection { private: TCPState * _state; friend class TCPState; void ChangeState(TCPState *); public: TCPConnection(); void ActiveOpen(void); void PassiveOpen(void); void Close(void); void Send(void); void Acknowledge(void); void Synchronize(void); };

An equivalent Java syntax is given by:

public class TCPConnection { private TCPState _state; private void ChangeState(TCPState ts) { ... } public TCPConnection() { ... } public void ActiveOpen() { ... } public void PassiveOpen() { ... } public void Close() { ... } public void Send() { ... } public void Acknowledge() { ... } public void Synchronize() { ... } };

The TCPConnection stores an internal TCPState data member. As we will see, the methods within each TCPState duplicate those within the TCPCon- nection. When these methods are invoked, they can in turn use the TCPCon- nection to perform TCP/IP related work as well as changing the TCPConnection object’s state.

The TCPState object is the next to be defined:

Software Development Methods 13 Memento, Observer, and State

class TCPState { protected: void ChangeState(TCPConnection *, TCPState *); public: virtual void ActiveOpen(void); virtual void PassiveOpen(void); virtual void Close(void); virtual void Send(void); virtual void Acknowledge(void); virtual void Synchronize(void); };

The equivalent Java class might appear as:

public class TCPState { protected void ChangeState(TCPConnection tc, TCPState ts); public void ActiveOpen() { ... } public void PassiveOpen() { ... } public void Close() { ... } public void Send() { ... } public void Acknowledge() { ... } public void Synchronize(void) { ... } };

Notice that in the C++ version of the code the TCPState is a friend of the TCPConnection. This isn’t possible in Java so we might have to get inventive with inner classes or package-level permissions. This can be done, but it isn’t necesarily pretty and its outside the scope of this discussion.

Because all of the logic for each state is embedded within the appropriate TCP- State subclasses, the TCPConnection delegates all operations to its own internal TCPState. This allows the connection to always choose the correct behavior for a given state since that behavior is defined within the current TCP- State object. Therefore the methods for the TCPConnection class can be defined as follows:

14 Software Development Methods Memento, Observer, and State

TCPConnection::TCPConnection() { _state = TCPClosed::Instance(); }

void TCPConnection::ChangeState(TCPState * s) { _state = s; }

void TCPConnection::ActiveOpen(void) { _state->ActiveOpen(this); }

void TCPConnection::PassiveOpen(void) { _state->PassiveOpen(this); }

void TCPConnection::Close(void) { _state->Close(this); }

void TCPConnection::Acknowledge(void) { _state->Acknowledge(this); }

void TCPConnection::Synchronize(void) { _state->Synchronize(this); }

All of the Java methods will be defined in a similar fashion. I won’t waste the paper to repeat them here.

By default, TCPState will provide hook methods for these calls. It is left to the derived classes of TCPState to implement state-specific functionality. For instance, let’s define the TCPClosed class which is used in the TCPConnec- tion constructor above:

class TCPClosed : public TCPState { public: static TCPState * Instance(void); virtual void ActiveOpen(TCPConnection *); virtual void PassiveOpen(TCPConnection *); };

Note that the TCPClosed class will be a singleton since there is no instance- specific data members. Now we can provide the necessary methods that are rele- vant to the TCPClosed state object. We can ignore the method from TCP-

Software Development Methods 15 Memento, Observer, and State

State that aren’t germane to TCPClosed because they were defined as hook methods in the base class:

void TCPClosed::ActiveOpen(TCPConnection * t) { // ... do connection stuff ChangeState(t, TCPEstablished::Instance()); }

void TCPClosed::PassiveOpen(TCPConnection * t) { ChangeState(t, TCPListen::Instance()); }

Again, the Java will be extremely similar and I won’t repeat the code here.

The idea here is that after performing any state-specific work, the individual state objects tell the TCPConnection object to change its state. Because each indi- vidual subclass of TCPState can be a singleton, we only need to invoke the Instance() method of the appropriate subclass to transition the TCPCon- nection into that new state.

16 Software Development Methods