Memento
Memento is a simple design pattern that stores the internal state of an object without violating the encapsulation principle. As the internal state is encapsulated within the object, the object must save the object data itself. The internal state can then be restored. The basic version of this pattern is not about the principle of history (undo and redo), but really just a single state that is saved and the object can be restored to it later. However, the principle of history can be implemented, even incrementally, to save only the changes against the original data. The pattern doesn't require any specific implementation of the state saving, we can use e.g. serialization for this purpose.
Motivation
In our applications, we may need an option to go back to the previous state in some places, for example, to get data from a form that the user has filled and the Internet connection has been lost when submitting it. We may also need to implement the undo/redo functions, these are handy whether you are programming a calculator or, for example, an editor. It might not surprise you that the pattern will separate this functionality into a separate object. This is, after all, the principle that most design patterns try to achieve. The original class keeping the state will remain clear from this logic and will be easier to maintain.
Pattern
The pattern includes the following classes:
Originator
- The class whose state we are storing. Allows to restore its state from a memento or save it to a new memento and return it.Memento
- The representation of the internal state of theOriginator
class. Just an object keeping the state without any logic.Caretaker
- The class saves/restores mementos from/to the originator, it's is a state manager.
Example
Imagine we want to keep the history of calculator expressions. To keep things simple, let's save only whole expressions as strings. We'll use the stack data structure to represent the history. In practice, of course, you can save objects with multiple complex properties as well. We can program a generic Memento, so we can use it for other classes and won't need to write new classes over and over again.
The Memento
class:
public class Memento<T> { private T data; public Memento(T data) { this.data = data; } public T getData() { return data; } }
The Originator
(Calculator) class:
public class Calculator<T> { private T expression; public Memento<T> save() { return new Memento(expression); } public void load(Memento<T> memento) { expression = memento.getData(); } public void setExpression(T expression) { this.expression = expression; } public T getExpression() { return expression; } // Other calculator methods... }
And the Caretaker
class:
public class Caretaker<T> { private Calculator<T> calculator; private Stack<Memento<T>> history = new Stack<Memento<T>>(); public Caretaker(Calculator calculator) { this.calculator = calculator; } public void save() { history.push(calculator.save()); } public void back() { calculator.load(history.pop()); } }
The use is as follows:
Calculator calculator = new Calculator(); Caretaker<String> history = new Caretaker<>(calculator); calculator.setExpression("1 + 1"); System.out.println(calculator.getExpression()); history.save(); calculator.setExpression("2 * 3"); System.out.println(calculator.getExpression()); history.back(); System.out.println(calculator.getExpression());
And the application output:
Console application
1 + 1
2 * 3
1 + 1
If you are interested how to program the calculation of such a mathematical expression, the Interpreter design pattern solves it, it's also from GOF.