19.设计模式-MEMENTO(备忘录)
一、模式定义与核心思想
备忘录模式是一种行为型设计模式,其核心目标是通过在不破坏对象封装性的前提下,捕获并保存其内部状态,并在需要时恢复至历史状态。该模式通过将状态管理与业务逻辑解耦,赋予系统以下核心能力:
- 状态回溯:支持撤销(Undo)、重做(Redo)操作(如文本编辑器的撤销功能)。
- 历史快照:保存对象的关键状态快照(如游戏存档、数据库事务回滚)。
- 封装保护:避免外部直接访问对象内部状态,确保数据安全性。
核心设计哲学:
- 状态隔离:通过独立备忘录对象存储状态,避免业务对象与状态管理逻辑耦合。
- 职责分离:发起者(Originator)专注于业务逻辑,管理者(Caretaker)专注状态生命周期管理。
典型应用场景:
- 文本编辑器的多级撤销/重做
- 游戏存档与读档系统
- 数据库事务的原子性保障
- 浏览器历史记录导航
二、模式组成与UML类图
核心角色
- Originator(发起者):
-
- 负责创建备忘录对象(
createMemento()),保存当前状态。 - 提供状态恢复接口(
restore(memento)),从备忘录加载历史状态。
- 负责创建备忘录对象(
- Memento(备忘录):
-
- 封装Originator的内部状态(如字段值、配置参数)。
- 对外仅暴露窄接口(如只读属性),保护数据完整性。
- Caretaker(管理者):
-
- 维护备忘录集合(如栈、列表),支持多版本状态管理。
- 不直接操作备忘录内容,仅负责存储与传递。
UML类图
classDiagram
class Originator {
-state: String
+createMemento(): Memento
+restore(memento: Memento): void
}
class Memento {
-state: String
+getState(): String
}
class Caretaker {
-mementos: List<Memento>
+save(memento: Memento): void
+retrieve(index: int): Memento
}
Originator --> Memento : 创建/恢复
Caretaker --> Memento : 存储/检索

三、代码实现示例
场景:实现文本编辑器的多级撤销功能
1. 备忘录与发起者类
// 备忘录类(仅暴露只读接口)
public class TextMemento {
private final String content;
public TextMemento(String content) { this.content = content; }
public String getContent() { return content; }
}
// 发起者类(文本编辑器)
public class TextEditor {
private String content;
public void write(String text) { content += text; }
public TextMemento save() {
return new TextMemento(content);
}
public void restore(TextMemento memento) {
this.content = memento.getContent();
}
public void print() {
System.out.println("当前内容: " + content);
}
}
2. 管理者类与客户端调用
// 管理者类(历史记录栈)
public class History {
private Stack<TextMemento> stack = new Stack<>();
public void push(TextMemento memento) {
stack.push(memento);
}
public TextMemento pop() {
return stack.pop();
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
History history = new History();
editor.write("Hello"); // 写入内容
history.push(editor.save()); // 保存状态1
editor.write(" World!");
history.push(editor.save()); // 保存状态2
editor.print(); // 输出: 当前内容: Hello World!
// 撤销到上一个状态
editor.restore(history.pop());
editor.print(); // 输出: 当前内容: Hello
}
}
四、工业级源码应用
- Java AWT/Swing撤销框架:
-
UndoManager类通过备忘录模式管理GUI操作历史,支持undo()和redo()。
- Spring框架事务管理:
-
@Transactional注解通过备忘录保存数据库连接状态,异常时回滚至事务开始点。
- 游戏引擎存档系统:
-
- Unity的
PlayerPrefs和Unreal Engine的SaveGame系统利用备忘录模式序列化游戏对象状态。
- Unity的
- 浏览器历史记录:
-
- Chrome的
History API通过栈结构存储页面状态,支持前进/后退导航。
- Chrome的
- 数据库事务日志:
-
- MySQL的
InnoDB引擎使用REDO/UNDO日志实现ACID特性,本质是备忘录模式的扩展。
- MySQL的
五、模式优劣与最佳实践
优势:
- 状态安全:通过私有构造函数和接口限制,防止外部篡改历史数据。
- 扩展灵活:支持多级撤销、分支存档等复杂场景(如Git版本控制)。
局限性:
- 内存消耗:频繁保存大对象可能导致内存溢出(需结合序列化存储优化)。
- 性能损耗:高频率状态保存场景需权衡性能(如实时游戏引擎)。
最佳实践:
- 增量快照:仅保存变化的部分(如Vue.js的虚拟DOM Diff算法)。
- 懒加载策略:延迟加载非活跃状态的备忘录(如浏览器标签页冻结)。
- 结合原型模式:通过深拷贝减少状态复制的开销。
总结
备忘录模式如同软件系统的“时间机器”,通过状态快照化和历史可追溯的设计理念,在编辑器、游戏、数据库等领域展现了强大的生命力。其核心价值在于将状态管理与业务逻辑解耦,开发者需重点把控备忘录的存储粒度与性能平衡,结合具体场景选择内存快照或持久化存储策略,从而构建出高可靠、易维护的系统架构。

浙公网安备 33010602011771号