Memento Pattern
The Memento design pattern is a behavioral design pattern that allows you to save and restore an object’s internal state without violating encapsulation. It’s particularly useful when you need to implement undo mechanisms or save snapshots of an object’s state.
The pattern suggests that we use a special object (i.e., Memento) to store the snapshot of the original object’s (i.e., Originator) state . The Memento objects are made immutable by having only the getter and no setter methods. Creating these objects is delegated to the Originator object, ensuring no other object can access its internal private state. Finally, we use an external object (i.e., Caretakers) to store Memento objects created by the Originator.
Structure
The Memento pattern consists of the following key components:
- Originator: is the object whose state is required to be saved and restored. Originator can save its current state in a Memento and also restore its state from a Memento
- Memento: is an object that stores the snapshot for the internal state of the Originator. The Memento’s state is immutable and can only be accessed by the Originator which generated it
- Caretaker: is responsible for managing multiple Memento’s for an object
When to use the Memento Pattern?
- When you want to be able to take snapshots of an object’s internal state and restore it when needed
- When you want a separate object to manage the snapshots instead of the one that generated them (
Single Responsibility Principle
)
Implementation Example
The code below demonstrates the Memento design pattern for a simple text editor application in Java. The TextEditor
class (Originator) manages the current text state and can create TextEditorMemento
objects to save its state. The TextEditorMemento
class (Memento) stores a snapshot of the text editor’s state. The TextEditorHistory
class (Caretaker) maintains a stack of mementos, allowing for undo operations. In the Solution
class, we create a text editor, add text in stages, save states, and then demonstrate the ability to restore previous states using the saved mementos.
import java.util.Stack;
// Client class
public class Solution {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
TextEditorHistory history = new TextEditorHistory();
editor.addText("Hello, ");
history.push(editor.save());
editor.addText("world!");
history.push(editor.save());
editor.addText(" How are you?");
editor.restore(history.pop());
System.out.println("After first restore: " + editor.getCurrentText());
editor.restore(history.pop());
System.out.println("After second undo: " + editor.getCurrentText());
}
}
// Memento class
class TextEditorMemento {
private final String text;
public TextEditorMemento(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
// Originator class
class TextEditor {
private StringBuilder currentText;
public TextEditor() {
this.currentText = new StringBuilder();
}
public void addText(String text) {
currentText.append(text);
System.out.println("Current State: " + currentText);
}
public String getCurrentText() {
return currentText.toString();
}
public TextEditorMemento save() {
System.out.println("Saving State...\n");
return new TextEditorMemento(currentText.toString());
}
public void restore(TextEditorMemento memento) {
System.out.println("\nRestoring State...");
this.currentText = new StringBuilder(memento.getText());
}
}
// Caretaker class
class TextEditorHistory {
private final Stack<TextEditorMemento> history = new Stack<>();
public void push(TextEditorMemento memento) {
history.push(memento);
}
public TextEditorMemento pop() {
if (!history.isEmpty()) {
return history.pop();
}
return null;
}
}
The output of the following program will be:
Current State: Hello,
Saving State...
Current State: Hello, world!
Saving State...
Current State: Hello, world! How are you?
Restoring State...
After first restore: Hello, world!
Restoring State...
After second undo: Hello,
Enjoyed the read? Give it a thumbs up 👍🏻!