概述
备忘录模式:(Memento Design Pattern)在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。
这个模式理解、掌握起来不难,代码实现比较灵活,应用场景也比较明确和有限,主要是用来防丢失、撤销、恢复等。
何时使用:
- 很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
UML 类图:
角色组成:
-
Memento: 包含了要被恢复的对象的状态。
-
Originator: 创建并在 Memento 对象中存储状态。
-
Caretaker: 对象负责从 Memento 中恢复对象的状态。
通用代码
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);
}
}
测试:
public class Test {
public static void main(String[] args) {
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("存档一");
originator.setState("存档二");
careTaker.add(originator.saveStateToMemento());
originator.setState("存档三");
careTaker.add(originator.saveStateToMemento());
originator.setState("存档四");
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());
}
}
结果:
Current State: 存档四
First saved State: 存档二
Second saved State: 存档三
具体实例
有这样一个经典实例:假设有这样一道面试题,希望你编写一个小程序,可以接收命令行的输入。用户输入文本时,程序将其追加存储在内存文本中;用户输入“:list”,程序在命令行中输出内存文本的内容;用户输入“:undo”,程序会撤销上一次输入的文本,也就是从内存文本中将上次输入的文本删除掉。
案例:
>hello
>:list
hello
>world
>:list
helloworld
>:undo
>:list
hello
代码实现:
Snapshot.java 相当于 Originator 角色:创建并在 Memento 对象中存储状态。
public class Snapshot {
private String text;
public Snapshot(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
InputText.java 相当于 Memento 角色:包含了要被恢复的对象的状态。
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 相当于 Caretaker 角色:对象负责从 Memento 中恢复对象的状态。
public class SnapshotHolder {
private Stack<Snapshot> snapshots = new Stack<>();
public Snapshot popSnapshot() {
return snapshots.pop();
}
public void pushSnapshot(Snapshot snapshot) {
snapshots.push(snapshot);
}
}
测试:
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);
}
}
}
}
结果:
总结
备忘录模式也叫快照模式,具体来说,就是在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。这个模式的定义表达了两部分内容:一部分是,存储副本以便后期恢复;另一部分是,要在不违背封装原则的前提下,进行对象的备份和恢复。
备忘录模式的应用场景也比较明确和有限,主要是用来防丢失、撤销、恢复等。它跟平时我们常说的“备份”很相似。两者的主要区别在于,备忘录模式更侧重于代码的设计和实现,备份更侧重架构设计或产品设计。