在实际开发中,我们常常会遇到这样的需求:某个对象需要恢复到之前的某个状态。例如:
- 文本编辑器的“撤销”功能
- 游戏的“读档”操作
- 表单的“重置”按钮
- 配置管理中的“恢复默认设置”
这些场景的本质就是保存历史快照,以便在需要的时候回滚。
什么是备忘录模式?
备忘录模式(Memento Pattern) 是一种行为型设计模式,用于在不破坏封装性的前提下,捕获一个对象的内部状态,并在之后将该对象恢复到原先的状态。
简单来说,就是保存和恢复对象状态。
模式角色结构
备忘录模式包含三个核心角色:
- Originator(发起人):负责创建备忘录对象,并可以使用备忘录恢复自己的状态。
- Memento(备忘录):用于存储发起人的内部状态,是一个只读对象,对外不暴露内部实现。
- Caretaker(管理者):负责保存和管理备忘录,但不能修改备忘录的内容。
实际应用举例
我们通过一个“文本编辑器”示例来理解备忘录模式:用户每输入一段内容,我们就保存一个快照;当用户点击“撤销”时,恢复到上一个快照。
四、代码实现
1. 发起人类 Editor
public class Editor {
private String text;
public void write(String input) {
this.text = input;
System.out.println("输入内容:" + text);
}
public String getText() {
return text;
}
// 创建备忘录
public EditorMemento save() {
return new EditorMemento(text);
}
// 恢复备忘录
public void restore(EditorMemento memento) {
this.text = memento.getText();
System.out.println("恢复内容:" + text);
}
}
2. 备忘录类 EditorMemento
public class EditorMemento {
private final String text;
public EditorMemento(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
3. 管理者类 Caretaker
import java.util.Stack;
public class Caretaker {
private Stack<EditorMemento> history = new Stack<>();
public void save(EditorMemento memento) {
history.push(memento);
}
public EditorMemento undo() {
if (!history.isEmpty()) {
return history.pop();
}
return null;
}
}
4. 客户端调用
public class Main {
public static void main(String[] args) {
Editor editor = new Editor();
Caretaker caretaker = new Caretaker();
editor.write("第一次输入");
caretaker.save(editor.save()); // 保存第一次状态
editor.write("第二次输入");
caretaker.save(editor.save()); // 保存第二次状态
editor.write("第三次输入"); // 没保存
System.out.println("--- 撤销一次 ---");
editor.restore(caretaker.undo());
System.out.println("--- 再次撤销 ---");
editor.restore(caretaker.undo());
}
}
输出结果
输入内容:第一次输入
输入内容:第二次输入
输入内容:第三次输入
--- 撤销一次 ---
恢复内容:第二次输入
--- 再次撤销 ---
恢复内容:第一次输入
小结
备忘录模式非常适合用于处理需要状态回退的场景,尤其是“撤销 / 重做”、“状态快照”、“历史版本”等功能。它把状态管理封装得非常好,不需要暴露内部结构,也不会破坏对象封装性。
优缺点
优点
- 满足开闭原则,不影响原类封装。
- 可以提供多个历史状态记录,方便回退。
- 适用于需要“撤销、恢复”功能的系统。
缺点
- 如果保存的状态较多或状态数据过大,会占用较多内存。
- 有时候可能需要定义多个备忘录类来保存不同的状态内容,增加了类的数量。
适用场景
- 编辑器中的撤销 / 重做
- 游戏存档和读档功能
- 表单重置和回退操作
- 配置恢复默认值