Memento: Snapshot & Restore
The Memento design pattern provides a way to save an object’s state and restore it later, while keeping the object’s internal representation encapsulated.
It is commonly used for undo/redo, checkpoints, game saves, drafts, and rollback.
1. The Problem
Consider a text editor:
TextDocument
+----------------------+
| text = "Hello" |
| cursor = 5 |
+----------------------+
An undo manager needs to remember this state.
One approach is to expose the fields:
document.getText();
document.getCursor();
Now the undo manager knows how TextDocument is implemented.
If the document later changes internally:
Before:
text + cursor
After:
DocumentTree + Cursor + Selection + Formatting
the undo manager may also need to change.
Memento avoids this coupling.
TextDocument
|
| save()
v
Memento
|
| store
v
UndoManager
The document creates its own snapshot, so it decides what needs to be saved.
2. Structure
There are three main participants.
+-------------------+
| Originator |
|-------------------|
| application state |
|-------------------|
| save() |
| restore(memento) |
+---------+---------+
|
| creates
v
+-------------------+
| Memento |
|-------------------|
| saved state |
+---------+---------+
^
|
| stores
+---------+---------+
| Caretaker |
|-------------------|
| history |
+-------------------+
Originator
The object whose state is being saved.
Memento
The snapshot of that state.
Caretaker
Stores and manages snapshots.
The Caretaker should not need to understand the snapshot’s internal data.
3. Basic Flow
save()
|
v
+-------------+ +-------------+
| Originator | ----> | Memento |
+-------------+ +-------------+
|
| store
v
+-------------+
| Caretaker |
+-------------+
Later:
Caretaker
|
| retrieve
v
Memento
|
| restore
v
Originator
The lifecycle is:
Create state
↓
Save
↓
Store snapshot
↓
Change object
↓
Retrieve snapshot
↓
Restore
4. Java Example
class TextDocument {
private String text = "";
private int cursor = 0;
void write(String value) {
text += value;
cursor = text.length();
}
Snapshot save() {
return new Snapshot(text, cursor);
}
void restore(Snapshot snapshot) {
text = snapshot.text();
cursor = snapshot.cursor();
}
record Snapshot(String text, int cursor) {}
}
The history manager:
class UndoManager {
private final Deque<TextDocument.Snapshot> history
= new ArrayDeque<>();
void checkpoint(TextDocument document) {
history.push(document.save());
}
void undo(TextDocument document) {
if (!history.isEmpty()) {
document.restore(history.pop());
}
}
}
Usage:
TextDocument document = new TextDocument();
UndoManager undo = new UndoManager();
document.write("Hello");
undo.checkpoint(document);
document.write(" World");
undo.undo(document);
The document returns to:
"Hello"
5. Why the Memento Helps
Without Memento:
UndoManager
|
+-- knows text
+-- knows cursor
+-- knows selection
+-- knows formatting
With Memento:
UndoManager
|
+-- knows only Memento
The Originator handles the details:
+----------------+
| Originator |
|----------------|
| knows state |
| knows Memento |
+----------------+
|
v
Memento
Caretaker
|
+-- stores Memento
+-- retrieves Memento
This separation is the main reason to use the pattern.
6. What Should a Memento Contain?
Only the information required to restore the state.
For example:
Document
+----------------+
| text | → save
| cursor | → save
| selection | → save
| cached wordCount| → don't need if recalculable
+----------------+
A good question is:
If I restore this Memento, can I get the Originator back to the required state?
If yes, the snapshot contains enough information.
7. Snapshot Independence
Be careful with mutable objects.
Suppose:
class Game {
private List<String> inventory;
}
This is potentially unsafe:
return new Snapshot(inventory);
because both the current game and snapshot may reference the same list.
Game --------+
|
v
List A
^
|
Snapshot ----+
A later modification changes the same list.
For mutable state, an independent copy may be required:
Game -------> List A
Snapshot ---> List B
Whether a deep copy is necessary depends on the object’s state and mutability.
8. Full Snapshots vs Deltas
The simplest approach is to save the complete state.
Snapshot A = full state
Snapshot B = full state
Snapshot C = full state
This makes restoration easy but can consume significant memory.
For large states, a system may store differences:
Snapshot A
|
Delta B
|
Delta C
|
Delta D
Other techniques include:
| Technique | Purpose |
|---|---|
| Bounded history | Limit memory usage |
| Coalescing | Combine frequent small changes |
| Deltas | Store only changes |
| Copy-on-write | Share unchanged data |
For example:
100 KB snapshot × 1,000 snapshots
≈ 100 MB
So unlimited full snapshots are not always practical.
9. Undo and Redo
Memento naturally works with history.
A simple undo stack:
+-----------+
| Snapshot C| ← newest
+-----------+
| Snapshot B|
+-----------+
| Snapshot A|
+-----------+
Redo usually requires another stack:
UNDO REDO
+-----------+ +-----------+
| Snapshot C| | Snapshot D|
| Snapshot B| +-----------+
| Snapshot A|
+-----------+
The history manager is responsible for deciding how these stacks behave.
10. Memento vs Command
Both can implement undo, but they save different things.
Command:
"Insert 'Hello'"
|
v
Undo = perform opposite operation
Memento:
Before operation
|
v
Snapshot
|
v
After operation
|
v
Undo = restore snapshot
| Command | Memento | |
|---|---|---|
| Stores | Operation | State |
| Undo | Reverse operation | Restore state |
| Memory | Usually smaller | Can be larger |
| Main challenge | Correct inverse | Complete snapshot |
| Good for | Structured operations | Whole-object state |
They can also be combined.
11. Memento vs Clone
They are related but have different purposes.
Clone:
Object → another copy of object
Memento:
Object → restorable representation of its state
A Memento does not necessarily have to be a complete copy of the runtime object.
12. Memento vs Serialization
Serialization can turn an object’s state into a persistent representation.
Memento is primarily about encapsulation and restoration.
They can be combined:
Originator
|
v
Memento
|
v
serialize
|
v
disk / database
For example, a game might create a Memento and then serialize it as a save file.
13. Internal vs External History
The Caretaker can be a separate object:
Document → Memento → UndoManager
or the Originator can manage its own history:
+----------------------+
| TextDocument |
|----------------------|
| current state |
| history |
| save() |
| restore() |
| undo() |
+----------------------+
A separate Caretaker is useful when history management is its own responsibility.
14. Common Real-World Uses
Memento
│
├── Text editor
│ └── Undo / redo
│
├── Drawing application
│ └── Previous canvas state
│
├── Games
│ └── Save games / checkpoints
│
├── Forms
│ └── Draft recovery
│
├── Configuration
│ └── Rollback
│
└── Workflows
└── Checkpoints
Database savepoints and VM checkpoints use similar rollback ideas, although they are not necessarily implementations of the GoF Memento pattern.
15. Performance Considerations
The basic pattern is simple, but production systems need to consider:
Memory
How many snapshots can exist?
snapshot size × history length
Copying cost
How expensive is creating a snapshot?
Restoration cost
How quickly can the object be rebuilt?
Mutable state
Does the snapshot need deep copying?
Frequency
Should every change create a checkpoint?
Often the answer is no.
For example, an editor might combine many keystrokes into one undo operation.
16. Common Mistakes
Exposing internal state
getInternalState()
just so another class can save it.
This defeats much of the encapsulation benefit.
Letting the Caretaker inspect the snapshot
snapshot.getText();
snapshot.getCursor();
The Caretaker generally shouldn’t need to do this.
Incomplete snapshots
If important state isn’t saved, restoration is incorrect.
Shallow copying mutable state
The snapshot can accidentally change when the current object changes.
Unlimited history
Full snapshots can consume large amounts of memory.
17. When to Use Memento
Memento is a good fit when:
Need previous state?
|
YES
|
v
Need to restore it later?
|
YES
|
v
Want to keep internal representation
hidden from the state manager?
|
YES
|
v
MEMENTO
It is especially useful when capturing the state is easier and safer than implementing inverse operations for every possible change.
18. When Not to Use It
Consider another approach when:
- The state is extremely large.
- Changes happen extremely frequently.
- Every operation has a simple inverse.
- Event history is more useful than state snapshots.
- The object contains resources that cannot meaningfully be snapshotted, such as live connections or threads.
Possible alternatives include:
Command
Event Sourcing
Deltas
Persistent data structures
Copy-on-write
Database savepoints
Premium Content
Unlock Memento and all premium lessons with a subscription.
From ₹199.99/year — See plans