备忘录模式 (Memento)
场景问题
问题案例
考虑一个文本编辑器,用户可以随时撤销(undo)和恢复(redo)编辑操作,需要保存历史状态。
不用模式的解决方案
实现简化版本
最直接的做法是用一个列表保存所有历史文本:
public class Editor {
private List<String> history = new ArrayList<>();
private String text = "";
public void setText(String newText) {
history.add(text);
text = newText;
}
public void undo() {
if (!history.isEmpty()) {
text = history.remove(history.size() - 1);
}
}
public String getText() { return text; }
}
使用示例
Editor editor = new Editor();
editor.setText("Hello");
editor.setText("Hello, World");
editor.undo();
System.out.println(editor.getText());
有何问题
- 只能保存简单状态,难以扩展。
- 状态管理与编辑器逻辑混杂,职责不清。
- 不能灵活保存和恢复多种类型的状态。
解决方案
备忘录模式的定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
应用备忘录模式的思路
- 定义备忘录类,封装需要保存的状态。
- 发起人创建和恢复备忘录。
- 管理者负责保存和管理备忘录对象。
备忘录模式的结构
- Originator:发起人,创建和恢复备忘录。
- Memento:备忘录,封装状态。
- Caretaker:管理者,保存和管理备忘录。
备忘录模式的实现
// 备忘录
public class Memento {
private String state;
public Memento(String state) { this.state = state; }
public String getState() { return state; }
}
// 发起人
public class Editor {
private String text = "";
public void setText(String text) { this.text = text; }
public String getText() { return text; }
public Memento createMemento() { return new Memento(text); }
public void restoreMemento(Memento m) { this.text = m.getState(); }
}
// 管理者
public class Caretaker {
private List<Memento> history = new ArrayList<>();
public void addMemento(Memento m) { history.add(m); }
public Memento getMemento() {
if (!history.isEmpty()) {
return history.remove(history.size() - 1);
}
return null;
}
}
使用示例
public class Client {
public static void main(String[] args) {
Editor editor = new Editor();
Caretaker caretaker = new Caretaker();
editor.setText("Hello");
caretaker.addMemento(editor.createMemento());
editor.setText("Hello, World");
caretaker.addMemento(editor.createMemento());
editor.setText("Hello, Java");
editor.restoreMemento(caretaker.getMemento());
System.out.println(editor.getText()); // 输出 Hello, World
editor.restoreMemento(caretaker.getMemento());
System.out.println(editor.getText()); // 输出 Hello
}
}
备忘录重写示例
示例结构
示例代码
见上文"备忘录模式的实现"部分。
模式讲解
备忘录模式的功能
- 实现对象状态的保存与恢复。
- 不破坏对象封装性。
- 支持多次撤销、恢复。
实现成接口
- 备忘录和发起人通常定义为类,也可用接口。
使用工厂方法
- 可结合工厂方法模式,统一创建备忘录对象。
切换产品簇
- 可用于切换不同的状态保存方案,如多文档编辑器。