Memento Pattern provides an ability to record an object internal state without violating encapsulation and reclaim it to previous state later without knowledge of the original object.
Participants in Memento Pattern
Memento Pattern is used by two objects.The originator and a caretaker.The originator is some object that has an internal state.Caretaker is going to perform some action to the originator,but wants to be able to undo the change.
- Caretaker first asks the originator for a memento object.
- Then it does what ever operations it was going to perform.
- To rollback the state before the operations,it returns the memento object to the originator.
- Memento object itself is an opaque object(one which the caretaker can not,or should not change.)
The solution is to wrap the state that you wish to preserve in an object, using Memento. A Memento is an object that contains the current internal state of the Originator object. Only the Originator can store and retrieve information from the Memento. To the outside world the Memento is just an arbitrary object.
Structure Summary
- Identify a class that needs to be able to take a snapshot of its state.(the originator role.)
- Design a class that does nothing more than accept and return this snapshot.(The memento role).
- Caretaker Role asks the Originator to return a Memento and cause the Originator's previous state to be restored of desired.
- Notion of undo or rollback has now been objectified(i.e promoted to full object status).
Discussion
Client requests a Memento from the source object when it needs to checkpoint the source object's state.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.
An unlimited "undo" and "redo" capability can be readily implemented with a stack of Command objects and a stack of Memento objects.
The Memento design pattern defines three distinct roles:
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.
Example
The Memento captures and externalizes an object's internal state so that the object can later be restored to that state. This pattern is common among do-it-yourself mechanics repairing drum brakes on their cars. The drums are removed from both sides, exposing both the right and left brakes. Only one side is disassembled and the other serves as a Memento of how the brake parts fit together. Only after the job has been completed on one side is the other side disassembled. When the second side is disassembled, the first side acts as the Memento. [Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]
Checklist
1. Identify the roles of "care taker" and "originator".
2. Originator creates a Memento and copies its state to that Memento.
3. Caretaker holds on to(but cannot peek into) the Memento.
4. Caretaker knows when to rollback the originator.
5. Originator reinstantes itself using the saved state in that Memento.
Rules of thumb
Command and Memento act as magic tokens to be passed around and invoked at a later time.In Command,the token represents a request,in Memento,it represents the internal state at a particular time.Polymorphism is important to Command but not to Memento because its interface is so narrow that a memento can only be passed as a value. [GoF, p346]
Command can use Memento to maintain the state required for an undo operation.[GoF, p242]
Memento can be used in conjuction with Iterator.An Iterator can use a Memento to capture the state of iteration.Iterator stores the Memento internally.[GoF, p271]
Classic examples of the memento pattern include the seed of a pseduorandom number generator.
Matthew Heaney says,
A memento is an alternate representation of another object,often in a format suitable for transmission across an external interface.
And programmers should be familar with this pattern,because it's used by the random number library to save and restore the state of a generator.
If we identify,This pattern is similar lot to serialization.As we know Serialization is done where the source object is stored and resurrected by another object and happens between different invocations of an application or between applications.Here the source object is still there and all that happens is state change. - Raptor Balaji
When to use Memento Pattern?
Use Memento Pattern when you need to be able to return an object to one of its previous states; for instance if your user requests and 'undo'.
Intent:
1. Saving the important state of system's key object.
2. Maintaining the key object's encapsulation.
Keeping the Single Responsibility Principle in mind, it is also a good idea to keep the state that you are saving seperate from the key object.
This seperate object that holds the state is known as the Memento object.
Using Memento Pattern,we can ask for an object for its current state,and it can track whatever changes are made using special semantics,rather than dumping the entire state and rereading later.
Example Code For Memento Pattern
Below example describes an implementation of Memento pattern.
Originator Class
class Originator {
private String state;
public void set(String state) {
System.out.println("Originator: Setting state to" + state);
this.state=state;
}
public Object saveToMemento() {
System.out.println("Originator: Saving to memento");
return new Memento(state);
}
public void restoreFromMemento(Object o) {
if(o instanceof Memento) {
Memento m=(Memento)o;
state=m.getSavedState();
System.out.println("Originator:State after restoring from Memento:" + state);
}
}
private static class Memento {
private String state;
public Memento(String stateToSave) {
state=stateToSave;
}
public String getSavedState() {
return state;
}
}
}
CareTaker
class CareTaker {
private List<Object> savedStates=new ArrayList<Object>();
public void addMemento(Object m) {
savedStates.add(m);
}
public Object getMemento(int index) {
return savedStates.get(index);
}
}
MementoPatternDemo
public class MementoPatternDemo {
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("State 3");
careTaker.addMemento(originator.saveToMemento());
originator.set("State 4");
originator.restoreFromMemento(careTaker.getMemento(1));
}
}
Advantages of Memento Pattern
1. Keeping the saved state external from key object helps to maintain cohesion.
2. Keeps the key object's data encapsulated.
3. Provides easy-to-implement recovery capability.
Drawbacks
1. Saving and restoring state may be time consuming.
2. In Java consider using serialization to save a system's state.
3. It exposes the internal structure of your object.
4. It enables the other object to arbitrarily change the state of your object.
No comments:
Post a Comment