summary
Memo pattern: (Memo design pattern) captures the internal state of an object without violating the encapsulation principle, and saves the state outside the object, so as to restore the object to its previous state later.
This mode is easy to understand and master. The code implementation is flexible, and the application scenarios are clear and limited. It is mainly used to prevent loss, revocation, recovery, etc.
When to use:
- Many times, we always need to record the internal state of an object. The purpose of this is to allow the user to cancel uncertain or wrong operations, restore to his original state, and make him have "regret medicine" to eat.
UML class diagram:
Role composition:
-
Memento: contains the state of the object to be restored.
-
Originator: creates and stores the state in the Memento object.
-
Caretaker: the object is responsible for restoring the state of the object from Memento.
General code
Memento.java
public class Memento { private String state; public Memento(String state){ this.state = state; } public String getState(){ return state; } }
Originator.java
public class Originator { private String state; public void setState(String state){ this.state = state; } public String getState(){ return state; } public Memento saveStateToMemento(){ return new Memento(state); } public void getStateFromMemento(Memento Memento){ state = Memento.getState(); } }
CareTaker.java
public class CareTaker { private List<Memento> mementoList = new ArrayList<Memento>(); public void add(Memento state){ mementoList.add(state); } public Memento get(int index){ return mementoList.get(index); } }
Test:
public class Test { public static void main(String[] args) { Originator originator = new Originator(); CareTaker careTaker = new CareTaker(); originator.setState("Archive I"); originator.setState("Archive II"); careTaker.add(originator.saveStateToMemento()); originator.setState("Archive III"); careTaker.add(originator.saveStateToMemento()); originator.setState("Archive IV"); System.out.println("Current State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(0)); System.out.println("First saved State: " + originator.getState()); originator.getStateFromMemento(careTaker.get(1)); System.out.println("Second saved State: " + originator.getState()); } }
result:
Current State: Archive 4
First saved State: Archive 2
Second saved State:
Specific examples
There is such a classic example: suppose there is such an interview question, I hope you can write a small program that can receive command line input. When the user inputs text, the program will append and store it in the memory text; The user inputs ": list", and the program outputs the contents of memory text in the command line; If the user enters ": undo", the program will undo the last text entered, that is, delete the last text from the memory text.
Case:
>hello
>:list
hello
>world
>:list
helloworld
>:undo
>:list
hello
Code implementation:
Snapshot.java is equivalent to the Originator role: create and store the state in the Memento object.
public class Snapshot { private String text; public Snapshot(String text) { this.text = text; } public String getText() { return text; } }
InputText.java is equivalent to the Memento role: it contains the state of the object to be restored.
public class InputText { private StringBuilder text = new StringBuilder(); public String getText() { return text.toString(); } public void append(String input) { text.append(input); } public Snapshot createSnapshot() { return new Snapshot(text.toString()); } public void restoreSnapshot(Snapshot snapshot) { this.text.replace(0, this.text.length(), snapshot.getText()); } @Override public String toString() { return text.toString(); } }
SnapshotHolder.java is equivalent to the Caretaker role: the object is responsible for restoring the state of the object from Memento.
public class SnapshotHolder { private Stack<Snapshot> snapshots = new Stack<>(); public Snapshot popSnapshot() { return snapshots.pop(); } public void pushSnapshot(Snapshot snapshot) { snapshots.push(snapshot); } }
Test:
public class Test { public static void main(String[] args) { InputText inputText = new InputText(); SnapshotHolder snapshotHolder = new SnapshotHolder(); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { String input = scanner.next(); if (input.equals(":list")) { System.out.println(inputText.toString()); } else if (input.equals(":undo")) { Snapshot snapshot = snapshotHolder.popSnapshot(); inputText.restoreSnapshot(snapshot); } else { snapshotHolder.pushSnapshot(inputText.createSnapshot()); inputText.append(input); } } } }
result:
summary
Memo mode is also called snapshot mode. Specifically, it captures the internal state of an object without violating the encapsulation principle, and saves the state outside the object, so as to restore the object to its previous state. The definition of this pattern expresses two parts: one is to store copies for later recovery; The other part is to backup and restore objects without violating the encapsulation principle.
The application scenarios of memo mode are also relatively clear and limited, which are mainly used to prevent loss, revocation, recovery, etc. It is very similar to what we often call "backup". The main difference between the two is that memo mode focuses more on code design and implementation, and backup focuses more on architecture design or product design.