The Problem
Undo and rollback are useful, but exposing every field of an object just so external code can save snapshots is risky. The object should keep control of its internals while still allowing state to be captured and restored at safe points.
The Solution
Memento lets the originator create opaque snapshots of its own state. In Go, the snapshot is usually an ordinary value with a narrow purpose, and the originator owns how that value is created and restored. A caretaker stores the snapshots without needing to understand the internals.
Structure
- Originator:
ShoppingCartowns the mutable state. - Memento:
CartMementostores a snapshot of lines and coupon state. - Caretaker:
CartHistorypushes and pops snapshots for undo. - Client: Decides when to save or restore checkpoints.
Implementation
This example snapshots a shopping cart before applying changes. The cart controls how deep copies are made, and the history object simply stores checkpoints for rollback.
package main
type CartLine struct {
SKU string
Qty int
}
type CartMemento struct {
lines []CartLine
coupon string
} Best Practices
- Let the originator define snapshot boundaries so internal invariants stay protected.
- Copy mutable slices or maps deeply when the memento needs isolation.
- Store snapshots only at meaningful checkpoints; full-history snapshots can be expensive.
- Use Memento for explicit rollback, not as a substitute for persistent storage.
- Keep the memento focused on state restoration rather than turning it into a generic DTO.
When to Use
- You need undo or rollback without exposing internals broadly.
- State can be snapshotted at clear moments in a workflow.
- The object should control how restoration happens.
When NOT to Use
- State is too large to snapshot cheaply and fine-grained commands are a better fit.
- Rollback can be modeled more simply through append-only events or command undo.
- The snapshot object would leak too much of the originator internals anyway.