I. Memento — Behavioral Pattern
Memento captures an object's internal state at a point in time, without breaking that object's encapsulation, so the state can be restored later. The object being snapshotted — the Originator — decides what goes into the snapshot and hands back an opaque Memento. A separate Caretaker holds onto that memento and is the one that decides when to restore it, but it never looks inside it.
This solves the problem of implementing undo/redo without exposing an object's private fields to the code that manages history. Without Memento, giving an editor undo support usually means either making its internal fields public so a history manager can copy them out, or hand-rolling a parallel state struct that has to be kept in sync by hand. Memento keeps the snapshot logic inside the object that owns the state, and keeps the history-management logic in a separate object that only ever passes mementos back and forth.
It's the same shape as a text editor's undo stack, or a database savepoint — the thing being modified knows how to snapshot and restore itself; the thing managing history just keeps a list of snapshots.
II. Real-world Example
A coffee shop order editor where a customer can undo their last change:
- OrderEditor (Originator) — holds the current
drinkNameandsize.Save()packages the current state into aMemento;Restore(memento)overwrites its own state from one;Snapshot()returns a human-readable string of the current order.
- Memento — an immutable value holding a
drinkNameandsize, with only getters (DrinkName(),Size()). Nothing outside themementopackage can construct or mutate one except throughOrderEditor.Save().
- History (Caretaker) — holds a slice of mementos.
Backup(editor)asks the editor to save its current state and appends it.Undo(editor)pops the last saved memento off the slice and asks the editor to restore it.
History never reads drinkName or size directly — it only ever calls Save() and Restore() on the editor and stores whatever comes back.

III. Implementation
order_editor.go
package memento
type OrderEditor struct {
drinkName string
size string
}
func NewOrderEditor(drinkName string, size string) *OrderEditor {
return &OrderEditor{drinkName: drinkName, size: size}
}
func (e *OrderEditor) SetDrinkName(drinkName string) {
e.drinkName = drinkName
}
func (e *OrderEditor) SetSize(size string) {
e.size = size
}
func (e *OrderEditor) Save() Memento {
return NewMemento(e.drinkName, e.size)
}
func (e *OrderEditor) Restore(memento Memento) {
e.drinkName = memento.DrinkName()
e.size = memento.Size()
}
func (e *OrderEditor) Snapshot() string {
return e.size + " " + e.drinkName
}memento.go
package memento
type Memento struct {
drinkName string
size string
}
func NewMemento(drinkName string, size string) Memento {
return Memento{drinkName: drinkName, size: size}
}
func (m Memento) DrinkName() string {
return m.drinkName
}
func (m Memento) Size() string {
return m.size
}history.go
package memento
type History struct {
states []Memento
}
func NewHistory() *History {
return &History{}
}
func (h *History) Backup(editor *OrderEditor) {
h.states = append(h.states, editor.Save())
}
func (h *History) Undo(editor *OrderEditor) string {
if len(h.states) == 0 {
return "No saved order state"
}
lastIndex := len(h.states) - 1
editor.Restore(h.states[lastIndex])
h.states = h.states[:lastIndex]
return "Restored order to " + editor.Snapshot()
}main.go (usage)
editor := memento.NewOrderEditor("Latte", "Medium")
history := memento.NewHistory()
history.Backup(editor)
editor.SetDrinkName("Mocha")
editor.SetSize("Large")
fmt.Println("Current order:", editor.Snapshot())
fmt.Println(history.Undo(editor))IV. Explain the example above
memento.NewOrderEditor("Latte", "Medium")creates an editor withdrinkName = "Latte",size = "Medium".
history.Backup(editor)callseditor.Save(), which returnsMemento{drinkName: "Latte", size: "Medium"}, and appends it tohistory.states.
editor.SetDrinkName("Mocha")andeditor.SetSize("Large")mutate the editor directly — the saved memento is untouched, since it's a separate value.
editor.Snapshot()now returns"Large Mocha".
history.Undo(editor)takes the last memento off the slice, callseditor.Restore(memento)to overwritedrinkNameandsizeback to"Latte"and"Medium", and removes that memento fromstates.
Running it produces:
*** Example Memento ***
Current order: Large Mocha
Restored order to Medium Latte
*** End of Memento ***History never touched drinkName or size directly — it only called Save(), stored the result, and later called Restore() with it. OrderEditor is the only code that knows what a memento actually contains.
V. Conclusion
Memento earns its keep when undo/redo or checkpoint/rollback needs to work without exposing an object's private state to whatever manages that history. Keeping the snapshot's shape inside the originator means the caretaker's code never breaks when the originator's internal fields change.
The trade-off is memory: every backup keeps a full copy of the state alive, and an unbounded history (like History.states here) grows forever unless something caps it. For state that's cheap to reconstruct from scratch, or an object that's only ever changed in one place, Memento's snapshot machinery is more ceremony than a simple "keep the old value in a local variable" would need. It pays off once undo needs to survive across multiple call sites, or once the state being tracked is too complex to safely copy by hand outside the object that owns it.
No pattern is universally superior.
VI. References
- Go Design Patterns (Mario Castro Contreras)




