Summary
Pattern Name | Memento Pattern |
Pattern Type | Behavioral Pattern |
Scope | Object |
Other Names | Token Undo |
Tagline | Store history of state change |
Use cases | 1. When we want to save the state of an object and restore that state later (like an undo feature in the app). 2. When we want to manage the internal state of an object without violating the encapsulation of that object. |
Related Patterns | Command Iterator |
Difficulty Level | Medium |
Implementations |
Definition
Memento pattern is responsible for maintaining the history of state change of an object. By keeping the history, Memento pattern ensures that we can check the object state history at any point, and also can revert any state change and move to the previous state.
State data of the object is not accessible from outside of the object, so data integrity of the state is ensured.
Main purpose of the Memento pattern is to store the state of object, so that it can move back and forth from the object’s history at any point in time.
On the other hand, the command pattern also enables keeping the history and enables undo, but the main purpose of the Command pattern is to wrap a command in an object, not the state history tacking.
Use Cases
Here are the use cases of Memento pattern-
- When we want to store the object’s state history, to move forward and backward in history.
- When we want to recover an object after an error or system crash.
Implementation
Memento pattern has 3 elements.
- Memento: class that we need to store the state history for.
- Originator: originator class is responsible for generating a new memento object, and set/unset the state of memento object.
- Caretaker: caretaker class is responsible for maintaining the history of the memento object. So this can be used to get the state of object in any particular situation, and also can be used to undo/revert any change done on the memento object.
Take a look at the implementation diagram.
Follow the steps below to implement Mediator pattern:
- Create a memento class. This class may be pre-existing.
- Implement function to get state of memento class.
- Create originator class. This class should be able to create a new Memento class object.
- Create caretaker class. Implement methods for setting state, getting state, and undoing (if required). In caretaker, maintain a list of memento objects whenever the state changes.
- In the client use originator to generate a new memento class. Perform the operation using the caretaker object.
Examples
Example #1: General Memento
Let’s take the example of a general memento.
Memento Related Classes
// Memento
class Memento
var state: string
constructor(stateParam: string)
state = stateParam
end constructor
method getState(): string
return state
end method
end class
// Originator
class Originator
var state: string
method setState(stateParam: string)
state = stateParam
end method
method getState(): string
return state
end method
method setMemento(): Memento
output "Memento Saved with timestamp => " + state
return new Memento(state)
end method
method getMementoState(Memento memento)
state = memento.getState()
end method
end class
// Caretaker
class Caretaker
var mementoList: memento[]
method add(Memento memento)
mementoList.add(memento);
end method
method getByIndex(int index): Memento
return mementoList.get(index);
end method
method getCurrent(): Memento
return mementoList.get(mementoList.size() - 1)
end method
method undo()
mementoList.remove(mementoList.size() - 1)
end method
end class
Demo
caretaker: Caretaker = new Caretaker()
originator: Originator = new Originator()
originator.setState("Time - 1 : " + System.currentTimeMillis())
caretaker.add(originator.setMemento())
originator.setState("Time - 2 : " + System.currentTimeMillis())
caretaker.add(originator.setMemento())
originator.setState("Time - 3 : " + System.currentTimeMillis())
caretaker.add(originator.setMemento())
output "Check state at index 1 (index starts at 0):"
stateAtIndex1: Memento = caretaker.getByIndex(1)
output stateAtIndex1.getState()
output "Check last state:"
lastState: Memento = caretaker.getCurrent()
output lastState.getState()
output "Undoing last state"
caretaker.undo()
output "Check last state after undo:"
lastStateAfterUndo: Memento = caretaker.getCurrent()
output lastStateAfterUndo.getState()
Output
Memento Saved with timestamp => Time - 1 : 1677470491085
Memento Saved with timestamp => Time - 2 : 1677470492106
Memento Saved with timestamp => Time - 3 : 1677470493113
Check state at index 1 (index starts at 0):
Time - 2 : 1677470492106
Check last state:
Time - 3 : 1677470493113
Undoing last state
Check last state after undo:
Time - 2 : 1677470492106
Code Implementations
Use the following links to check Memento pattern implementation in specific programming languages.