The Memento Pattern is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.
It is the standard way to implement "Undo" (Ctrl+Z) or Checkpoints in software.
The Problem
Imagine you are building a Text Editor or a Game. You want the user to be able to "Undo" an action.
- To do this, you need to save the object's internal state.
- However, most objects have
privatefields for a reason (Encapsulation). If you make all fields public just so another class can save them, you break the security and structure of your code.
The Solution: The Memento
The pattern uses three roles:
- Originator: The object whose state we want to save (e.g., the Editor). It creates the Memento.
- Memento: A small, "opaque" object that stores the state. It doesn't allow other classes to see what's inside.
- Caretaker: The object that keeps track of the Mementos (the "Undo Stack"). It never modifies or looks inside the Memento.
Step-by-Step Java Implementation
1. The Memento
A simple class that holds the data.
public class EditorMemento {
private final String content;
public EditorMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
2. The Originator
The class that creates the state and can restore itself from a memento.
public class Editor {
private String content;
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public EditorMemento save() {
return new EditorMemento(content);
}
public void restore(EditorMemento memento) {
this.content = memento.getContent();
}
}
3. The Caretaker
Manages the history of mementos.
import java.util.Stack;
public class History {
private Stack<EditorMemento> states = new Stack<>();
public void push(EditorMemento state) {
states.push(state);
}
public EditorMemento pop() {
return states.pop();
}
}
Full Code for Testing
// Save as MementoTest.java
import java.util.Stack;
// 1. The Memento (Immutable state storage)
class Memento {
private final String state;
public Memento(String state) { this.state = state; }
public String getState() { return state; }
}
// 2. The Originator (The object being tracked)
class TextEditor {
private String text;
public void setText(String text) {
this.text = text;
System.out.println("Editor: Current text is -> " + text);
}
public Memento save() {
return new Memento(text);
}
public void restore(Memento memento) {
this.text = memento.getState();
}
public String getText() { return text; }
}
// 3. The Caretaker (History manager)
class UndoManager {
private Stack<Memento> history = new Stack<>();
public void save(TextEditor editor) {
history.push(editor.save());
}
public void undo(TextEditor editor) {
if (!history.isEmpty()) {
editor.restore(history.pop());
} else {
System.out.println("History is empty!");
}
}
}
// 4. Test
public class MementoTest {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
UndoManager undoManager = new UndoManager();
System.out.println("--- Memento Pattern: Undo Test ---\n");
// First Action
editor.setText("Version 1.0");
undoManager.save(editor);
// Second Action
editor.setText("Version 2.0 (The buggy one)");
System.out.println("\n[System] Performing Undo...");
undoManager.undo(editor);
System.out.println("Editor: Restored text is -> " + editor.getText());
System.out.println("\n--- Restore Successful ---");
}
}
Why use Memento?
- Encapsulation: You can save and restore state without exposing the object's
privatevariables to the rest of the app. - Simplified Originator: The object doesn't need to manage its own history; the Caretaker does that.
- Safety: By making the Memento immutable (using
final), you ensure the state cannot be changed while it is sitting in the history stack.
Real-World Example
- Git: Every "commit" is essentially a Memento of the project's state at a point in time.
- Video Games: "Save Slots" or "Checkpoints" use this pattern to store player stats, position, and inventory.