Instructor: Stefan Mitsch
Notification editor, save and undo text edits
public class Editor { private String text; private long cursorPos; // ... }
Command
Memento takes a snapshot of an object's internal state
Problem illustration:
How to store the internal state without breaking encapsulation?
Problem
Want to store object's internal state without violating encapsulation
Intent
Structure
Based on nested classes
The Originator class produces a snaptshot of its own state, and restores its state from snapshots
Originator
The Memento is a value object that has fields to hold the Originator state; a Mememto should be immutable and only be initialized through the constructor.
Memento
Mememto
The Caretaker knows when to capture and restore the state of the Originator; the Caretaker can keep track of the history and pass previous snapshots to the Originator to restore its state.
Caretaker
In this implementation, the Memento is a nested class and has a private constructor, so that only the originator can create it; even though the Memento has access to the private fields of the Originator, the Caretaker has very limited access.
private
For programming languages without support for nested classes
The Originator class produces a snapshot of its own state by instantiating a ConcreteMemento class; all others work with the memento through the Memento interface
ConcreteMemento
The Memento has all public getters and setters, so that the Originator can work with it
public
Multiple types of Originator and Memento; each originator works with a corresponding memento; neither one has public getters to expose their state to anyone
The Caretaker is now explicitly restricted from accessing state in the Memento and entirely decoupled from the Originator
Each memento is linked to the originator that produced it; the originator passes its state to the memento through its constructor; the memento knows how to set the state of the originator.
public interface NumberCommand { int execute(); } public class RandomNumberCommand { private Random r = new Random(); public int execute() { return r.nextInt(); } } public class NumberStore { private int number; public static class Memento { private int n; private Memento(int n) { this.n = n; } private int getNumber() { return n; } } public Memento save() { return new Memento(number); } public void restore(Memento m) { number = m.getNumber(); } public void do(NumberCommand c) { number = c.execute(); } } public class History { private List<NumberGenerator.Memento> history = List.of(); private NumberStore store; public History(NumberStore store) { this.store = store; } public void do(NumberCommand c) { history.add(store.save()); store.do(c); } public void undo() { store.restore(history.removeLast()); } } public class Demo { public static void main(String[] args) { NumberStore s = new NumberStore(); History h = new History(s) h.do(new RandomNumberCommand()); h.do(new RandomNumberCommand()); h.undo(); } }