The memento pattern is a software design pattern that
provides the ability to restore an object to its previous state (undo via
rollback).
The intent of the memento pattern is to capture the internal state of an object without violating encapsulation so that the object can be restored to required previous state.
The intent of the memento pattern is to capture the internal state of an object without violating encapsulation so that the object can be restored to required previous state.
Memento pattern is used to implement this in such a way that the saved state data of the object is not accessible outside of the object; this protects the integrity of saved state data.
Database Transactions
Mechanism of rolling back the transaction can be achieved by memento design pattern.
Participants
The classes and objects participating in this pattern are:
Memento - It is a POJO which maintains the state of the originator.
Originator - The originator is some object that has an internal state.
Caretaker - Caretaker is the object that keeps track of multiple mementos. It maintains the mementos like save points.
Example of memento pattern
Most of the editors use the memento pattern to store the previous states so user can restore them when it required. Like in notepad, 'Ctrl+Z' is used to Undo an action and 'Ctrl+Y' is used to Redo the last action or repeat an action.
Memento.java
public class Memento {
private String state;
public Memento(String state){
this.state = state;
}
public String getState(){
return state;
}
}
FileWriterUtil.java
public class FileWriterUtil {
private String state;
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public Memento saveStateToMemento(){
return new Memento(state);
}
public void getStateFromMemento(Memento Memento){
state = Memento.getState();
}
}
FileCareTaker.java
import java.util.ArrayList;
import java.util.List;
public class FileCareTaker {
private List<Memento> mementoList = new ArrayList<Memento>();
public void add(Memento state){
mementoList.add(state);
}
public Memento get(int index){
return mementoList.get(index);
}
}
FileHandlerClient.java
public class FileHandlerClient {
public static void main(String[] args) {
FileWriterUtil originator = new FileWriterUtil();
FileCareTaker careTaker = new FileCareTaker();
originator.setState("State#1");
originator.setState("State#2");
/*save the current state. i.e#State#2*/
careTaker.add(originator.saveStateToMemento());
originator.setState("State#3");
/*save the current state. i.e#State#3*/
careTaker.add(originator.saveStateToMemento());
originator.setState("State#4");
System.out.println("Current State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(0));
System.out.println("First saved State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(1));
System.out.println("Second saved State: " + originator.getState());
}
}
Output:
Current State: State#4
First saved State: State#2
Second saved State: State#3
The examples in Java's core libraries
java.util.Date (the setter methods do that, Date is internally represented by a long value)
All implementations of java.io.Serializable
All implementations of java.io.Serializable
All implementations of javax.faces.component.StateHolder.
Important points
Important points
Memento pattern is very easy to implement, however, we need to take care that Memento class should be accessible by Originator object only. We should use the caretaker object for saving and restoring the originator state.
Sometimes Originator object has properties that are not immutable; we should use deep copy or cloning to avoid data integrity and security issue. If deep cloning is very complex, Serialization is the best way to achieve this.
One drawback of this pattern, if Originator object is very huge then Memento object size will also be huge and use a lot of memory.