Problem

Sometimes we would like to store an object's state in order to restore that later. How do we support "undo" and "rollback" operations?

Solution

Give the object whose state you would like to save the ability to serialize its internal state. The "Memento" created when the object is serialized is stored in a stack-like fashion by some storage object. When we would like to restore the state, the storage object requests the Originator object to recreate the state based on the Memento.

Related Patterns

Discussion

Source object is the only actor able to access the insides of a Memento. The storage object ("caretaker") only knows when to tell the object to create a Memento and when to restore it.

Examples

In combination with a stack of Command objects, unlimited "undo" and "redo" can be easily implemented.

Iterators can be implemented to use a Memento to store the current state of an iteration.

Code

Here we have three Java classes: Memento, Originator, and Manager. Originator has additional temporary data that is not necessary to restore a state from. The Manager class is the caretaker of the Mementos: we can add and get Mementos from the Manager. Note that there is no way to modify the information in a Memento after is creation.

class Memento{
  private String state;
  public Memento(String state){this.state = state;}
  public getSavedState(){return state;}
}
class Originator{
  private String state;
  public void set(String state){this.state = state;}
  public Memento saveToMemento(){return new Memento(state);}
  public void restoreFromMemento(Memento m){state = m.getSavedState();}
}
class Manager{
  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 Demo{
  public static void main(String[] args){
    Manager manager = new Manager();
    Originator originator = new Originator();
    originator.set("foo");
    manager.addMemento(originator.saveToMemento());
    originator.set("bar");
    manager.addMemento(originator.saveToMemento());
    originator.set("baz");
    originator.restoreFromMemento(manager.getMemento(1));
  }
}