文章目录
- 1. 引言:为什么“撤销”这么难?
- 2. 什么是备忘录模式
- GoF 定义
- 3. 备忘录模式的核心思想
- 4. 备忘录模式的结构
- 5. 示例:文本编辑器撤销功能
- 5.1 备忘录类(不可变)
- 5.2 发起人
- 5.3 管理者
- 5.4 客户端使用
- 6. 备忘录模式的优点
- 7. 备忘录模式的缺点
- 8. 备忘录 vs 命令
- 9. 备忘录 vs 状态模式
- 10. JDK / 框架中的备忘录思想
- 数据库事务
- 11. 适用场景
- 12. 一个常见误区
- 参考
1. 引言:为什么“撤销”这么难?
在日常软件中,“撤销 / 回滚”几乎无处不在:
- 编辑器的 Ctrl + Z
- 游戏存档
- 事务回滚
- 配置快照
最直接的想法是:
classEditor{Stringtext;}直接暴露字段保存?
- 破坏封装
- 状态越来越复杂
- 外部对象不该知道内部细节
备忘录模式的目标:保存状态,但不暴露内部结构。
备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,很多软件都提供了撤销(Undo)操作,如 Word、记事本、Photoshop、IDEA等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;还有在 浏览器 中的后退键、数据库事务管理中的回滚操作、玩游戏时的中间结果存档功能、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。
2. 什么是备忘录模式
GoF 定义
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
详细解释:又叫快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。
一句话理解:
状态交给“备忘录”保存。
3. 备忘录模式的核心思想
备忘录模式解决的问题是:
- 如何保存对象内部状态
- 如何恢复历史状态
- 不让外部对象直接操作内部细节
状态属于对象,但保存权不属于对象自己。
4. 备忘录模式的结构
备忘录模式包含三个角色:
- Originator(发起人):需要保存状态的对象
记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
- Memento(备忘录):状态快照
负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
- Caretaker(管理者):保存备忘录,但不解析内容
对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
5. 示例:文本编辑器撤销功能
5.1 备忘录类(不可变)
publicclassEditorMemento{privatefinalStringcontent;publicEditorMemento(Stringcontent){this.content=content;}publicStringgetContent(){returncontent;}}5.2 发起人
publicclassEditor{privateStringcontent;publicvoidwrite(Stringtext){content=text;}publicEditorMementosave(){returnnewEditorMemento(content);}publicvoidrestore(EditorMementomemento){this.content=memento.getContent();}publicStringgetContent(){returncontent;}}5.3 管理者
importjava.util.Stack;publicclassHistory{privateStack<EditorMemento>stack=newStack<>();publicvoidpush(EditorMementomemento){stack.push(memento);}publicEditorMementopop(){returnstack.pop();}}5.4 客户端使用
Editoreditor=newEditor();Historyhistory=newHistory();editor.write("Hello");history.push(editor.save());editor.write("Hello World");history.push(editor.save());editor.write("Hello World!!!");editor.restore(history.pop());System.out.println(editor.getContent());6. 备忘录模式的优点
- 不破坏封装
- 支持撤销 / 回滚
- 状态管理职责清晰
- 符合单一职责原则
7. 备忘录模式的缺点
- 状态快照占内存
- 深拷贝成本高
- 状态过多时管理复杂
8. 备忘录 vs 命令
| 维度 | 备忘录 | 命令 |
|---|---|---|
| 关注点 | 状态保存 | 行为封装 |
| 是否支持撤销 | 是 | 是 |
| 实现方式 | 状态快照 | 反向操作 |
9. 备忘录 vs 状态模式
| 模式 | 解决的问题 |
|---|---|
| 备忘录 | 保存历史状态 |
| 状态 | 行为随状态变化 |
10. JDK / 框架中的备忘录思想
数据库事务
- undo log
- savepoint
本质上就是备忘录思想。
11. 适用场景
- 编辑器
- 游戏存档
- 事务系统
- 快照 / 回滚
12. 一个常见误区
备忘录不是简单的 getter/setter,而是“受控的状态快照”。
参考
备忘录模式 | 菜鸟教程
《图解设计模式》
备忘录 - Java教程 - 廖雪峰的官方网站
备忘录设计模式