For an undo feature, when would you choose Memento (snapshots) over a Command-based approach, and how can the two combine?
answer
- Memento = restore previous state; Command = apply inverse
- Memento wins when inverses are hard; Command wins for big state + small edits
- Command gives a replayable op log (redo, macros)
- Hybrid: Command stores a Memento to undo itself
- Bound history to control memory either way
basics
~20 sMemento undoes by restoring a saved full state; Command undoes by storing each operation and applying its inverse. Use Memento when full snapshots are cheap and inverses are hard to compute; use Command when state is large but each change is small. They combine: a Command can store a Memento to undo itself.
solid answer
~50 sBoth patterns support undo but capture different things. Memento stores the Originator's full state at each step and undoes by restoring a previous snapshot — simple and robust when computing the inverse of an operation would be hard, but memory-heavy because each snapshot duplicates state. Command stores each user action as an object (often with an explicit inverse) and undoes by executing the inverse — memory-efficient for large state with small edits, and it naturally records the operation history, but it requires every command to know how to reverse itself, which is awkward for lossy or hard-to-invert operations. Choose Memento when state is small or inverses are impractical; choose Command when state is large and edits are small and invertible. The two combine cleanly: a Command captures a Memento of just the affected state before executing, and its undo restores that memento. This gives Command's per-operation history plus Memento's no-need-to-invert restore, at the cost of storing a snapshot per command.
go deeper
Knows both Memento and Command can implement undo, even without articulating the trade-off precisely.
States the core distinction (restore state vs apply inverse) and picks the right one for an obvious case.
Reasons about memory vs invertibility, recognizes lossy-operation cases, and can design the Command-holds-Memento hybrid.
Chooses an undo architecture for a whole product (snapshot vs op-log vs hybrid), accounting for redo/macros/collaboration, memory budgets, and history-bounding policy.
## The undo problem, two ways To undo a change you need one of two things: the **state before** the change (so you can restore it), or the **inverse of the operation** that made the change (so you can reverse it). These map to two patterns. ### Memento — store the state before The Caretaker asks the Originator for a **snapshot** before each change. Undo = restore the most recent snapshot. - **Strengths:** you never have to figure out how to *reverse* an operation — you just put the old state back. This is invaluable for operations that are hard or impossible to invert (e.g. a filter that loses information, a complex recomputation). - **Weaknesses:** every step stores a full (often deep) copy of the state, so memory grows with history length. For large documents this is expensive. ### Command — store the operation Each user action is reified as a **Command** object with `execute()` and `undo()` (the inverse). The history is a stack of executed commands; undo pops one and calls its `undo()`. - **Strengths:** memory-cheap when the state is large but each edit is small — you store just 'insert "x" at position 5', not the whole document. You also get a clean, replayable log of operations (useful for redo, macros, collaboration, auditing). - **Weaknesses:** every command must know how to invert itself, which is hard for **lossy** operations (once data is gone, the inverse can't reconstruct it) and adds complexity. ## How to choose | Situation | Prefer | |---|---| | State is small / cheap to copy | Memento | | Operations are hard or impossible to invert | Memento | | State is large but each change is small | Command | | You need a replayable operation log / redo / macros | Command | | Memory for many snapshots is a concern | Command (or Memento with deltas) | ## Combining them — Command holds a Memento The two are not exclusive; a very common hybrid lets each Command undo itself by **snapshotting only the state it touches**: ```java interface Command { void execute(); void undo(); } class EditCommand implements Command { private final Editor editor; private Editor.Memento before; // a Memento captured before executing EditCommand(Editor editor) { this.editor = editor; } public void execute() { before = editor.save(); editor.applyEdit(); } public void undo() { editor.restore(before); } // no inverse logic needed } ``` Now you get **Command's** per-operation history and redo/macro support, while each command's `undo()` simply **restores a Memento** instead of computing an inverse. The trade-off is that you store a snapshot per command — so this hybrid leans back toward Memento's memory cost, mitigated by snapshotting *only the affected sub-state* rather than the whole Originator. ## Memory-cost reminder Whichever you pick, an unbounded undo history grows memory over time. Bound it: cap history depth, evict oldest entries, or store deltas. Memento-heavy designs feel this most; Command-of-small-edits the least. ## Summary Memento answers undo by **remembering what things were**; Command answers it by **remembering what was done**. Pick by the cost of copying state vs the cost (and feasibility) of inverting operations — and combine them when you want history plus snapshot-based restore.
- Why is a lossy operation (one that discards information) easier to undo with Memento than with a pure Command inverse?Because the discarded information can't be reconstructed by an inverse operation. Memento sidesteps this by having saved the full prior state, so restoring it brings the lost data back regardless of how lossy the operation was.
- In the hybrid where a Command stores a Memento, what determines whether memory cost is acceptable?How much state each Memento captures. If each command snapshots only the small sub-state it affects (not the whole Originator) and the history is bounded, the cost stays modest; snapshotting the entire document per command does not scale.
saying these in an interview costs you the question
- Claiming Memento and Command are interchangeable with no trade-offs
- Saying Command always uses less memory — not if you snapshot per command
- Forgetting that lossy operations can't be inverted, favoring Memento
- Ignoring memory growth of an unbounded snapshot history