Definition
To record an object internal state without violating encapsulation and reclaim it later without knowledge of the original object.Intent
01- Without violating encapsulation, capture and externalize an object’s internal state so that the object can be returned to this state later.
- A magic cookie that encapsulates a “check point” capability.
- Promote undo or rollback to full object status.
Problem
02Need to restore an object back to its previous state (e.g. “undo” or “rollback” operations).
Structure
Where to use & benefits
- Let some info in an object to be available by another object by using default access control.
- Save some info for later uses.
- Need undo/redo features.
- Used in database transaction.
- Related patterns include
- Command, which supports undo or redo features, whereas a memento keeps state of an object.
- Iterator, which provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation, whereas a memento can be used for iteration.
Motivation
It is sometimes necessary to capture the internal state of an object at some point and have the ability to restore the object to that state later in time. Such a case is useful in case of error or failure. Consider the case of a calculator object with an undo operation such a calculator could simply maintain a list of all previous operation that it has performed and thus would be able to restore a previous calculation it has performed. This would cause the calculator object to become larger, more complex, and heavyweight, as the calculator object would have to provide additional undo functionality and should maintain a list of all previous operations. This functionality can be moved out of the calculator class, so that an external (let’s call it undo manager class) can collect the internal state of the calculator and save it. However providing the explicit access to every state variable of the calculator to the restore manager would be impractical and would violate the encapsulation principle.
Intent
- The intent of this pattern is to capture the internal state of an object without violating encapsulation and thus providing a mean for restoring the object into initial state when needed.
Implementation
The figure below shows a UML class diagram for the Memento Pattern:- Memento
- Stores internal state of the Originator object. The state can include any number of state variables.
- The Memento must have two interfaces, an interface to the caretaker. This interface must not allow any operations or any access to internal state stored by the memento and thus honors encapsulation. The other interface is to the originator and allows the originator to access any state variables necessary to for the originator to restore previous state.
- Originator
- Creates a memento object capturing the originators internal state.
- Use the memento object to restore its previous state.
- Caretaker
- Responsible for keeping the memento.
- The memento is opaque to the caretaker, and the caretaker must not operate on it.
Discussion
03The client requests a Memento from the source object when it needs to checkpoint the source object’s state. The source object initializes the Memento with a characterization of its state. The client is the “care-taker” of the Memento, but only the source object can store and retrieve information from the Memento (the Memento is “opaque” to the client and all other objects). If the client subsequently needs to “rollback” the source object’s state, it hands the Memento back to the source object for reinstatement.
04An unlimited “undo” and “redo” capability can be readily implemented with a stack of Command objects and a stack of Memento objects.
05The Memento design pattern defines three distinct roles:
06- Originator - the object that knows how to save itself.
- Caretaker - the object that knows why and when the Originator needs to save and restore itself.
- Memento - the lock box that is written and read by the Originator, and shepherded by the Caretaker.
Memento in Java
Why read if you can watch?
Watch design patterns video tutorialimport java.util.*;
class Memento {
private String state;
public Memento(String stateToSave) { state = stateToSave; }
public String getSavedState() { return state; }
}
class Originator {
private String state;
/* lots of memory consumptive private data that is not necessary to define the
* state and should thus not be saved. Hence the small memento object. */
public void set(String state) {
System.out.println("Originator: Setting state to "+state);
this.state = state;
}
public Memento saveToMemento() {
System.out.println("Originator: Saving to Memento.");
return new Memento(state);
}
public void restoreFromMemento(Memento m) {
state = m.getSavedState();
System.out.println("Originator: State after restoring from Memento: "+state);
}
}
class Caretaker {
private ArrayList<Memento> savedStates = new ArrayList<Memento>();
public void addMemento(Memento m) { savedStates.add(m); }
public Memento getMemento(int index) { return savedStates.get(index); }
}
class MementoExample {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Originator originator = new Originator();
originator.set("State1");
originator.set("State2");
caretaker.addMemento( originator.saveToMemento() );
originator.set("State3");
caretaker.addMemento( originator.saveToMemento() );
originator.set("State4");
originator.restoreFromMemento( caretaker.getMemento(1) );
}
}
No comments:
Post a Comment