
设计模式-备忘录模式
设计模式之备忘录模式
1. 概述
备忘录模式是一种行为型设计模式,它允许在不暴露对象内部状态的情况下保存对象的内部状态,并在以后可以恢复到先前的状态。 它主要用于撤销操作、版本控制等场景。
2. 使用场景
- 需要保存和恢复对象内部状态,且不希望暴露对象内部结构时。 这是备忘录模式的核心应用场景。
- 需要实现撤销/重做 (Undo/Redo) 功能时。 例如,文本编辑器、图像编辑器等。
- 需要进行事务回滚时。 在数据库操作中,可以使用备忘录模式来保存事务开始前的状态,以便在事务失败时回滚到初始状态。
- 需要创建对象的快照 (Snapshot) 用于历史记录或审计时。 例如,游戏中的存档功能。
- 工作流或者流程审批:在工作流系统中,一个流程实例可能需要经历多个状态,并且可能需要回退到之前的某个状态。备忘录模式可以用来保存流程实例的状态,以便在需要时进行回退。
3. 优缺点
备忘录模式的优点:
- 保存和恢复对象的状态: 备忘录模式允许在不破坏封装性的前提下,保存和恢复对象的状态。 发起人可以完全控制存储和恢复状态的细节。
- 实现撤销/重做功能: 备忘录模式可以用来实现撤销/重做功能。 允许多个状态的保存和恢复,实现多级撤销。
- 支持版本控制: 备忘录模式可以用来实现版本控制。
- 符合单一职责原则: 将状态的保存和恢复的职责分离到备忘录类中,符合单一职责原则。
备忘录模式的缺点:
- 存储成本: 如果需要保存的状态很多,或者状态对象很大,那么存储备忘录对象的成本可能会很高。 需要考虑备忘录对象的生命周期管理,避免内存泄漏。
- 复杂性: 备忘录模式可能会增加代码的复杂性,特别是当状态对象比较复杂时。 需要仔细设计备忘录类的结构,以及发起人和负责人之间的交互。
- 负责人职责不明确: 负责人只负责存储备忘录对象,不参与状态的修改,这可能导致负责人类的职责不够明确。
4. 代码示例
示例:文本编辑器
还是以一个简单的文本编辑器为例。 文本编辑器允许用户输入文本,并提供撤销功能。 我们可以使用备忘录模式来保存文本编辑器的状态(即文本内容),并在用户需要撤销时,恢复到之前的状态。
代码实现
1 | // 1. 备忘录 (Memento) 类 |
5. 运行结果
1 | 保存状态: 这是第一版内容 |
关键点说明:
EditorMemento(备忘录类):- 负责存储
TextEditor的内部状态 (text)。 EditorMemento对象只包含状态信息,并且不提供修改状态的方法 (只读)。 这保证了TextEditor的状态只能通过TextEditor本身来修改,避免了外部直接修改状态导致的问题.
- 负责存储
TextEditor(发起人类):TextEditor是我们要保存状态的对象。setText()方法用于设置文本内容。save()方法创建一个EditorMemento对象,保存当前TextEditor的状态 (创建一个快照)。restore()方法从EditorMemento对象恢复TextEditor的状态。
History(负责人):History负责保存和管理备忘录对象。- 它使用
List来存储EditorMemento对象。 push()方法将EditorMemento对象添加到List中。pop()方法从List中移除并返回最后一个EditorMemento对象 (实现撤销功能)。
MementoPatternDemo(客户端):- 客户端代码创建
TextEditor和History对象。 - 客户端代码设置
TextEditor的文本内容,并使用history.push(editor.save())保存状态。 - 客户端代码可以使用
history.pop()获取之前的EditorMemento对象,并使用editor.restore()恢复到之前的状态。
- 客户端代码创建
6. 注意事项
- 备忘录的不可变性: 备忘录对象一旦创建,就不应该被修改。这保证了状态的安全性。 可以将备忘录类设计为不可变类。
- 负责人不修改备忘录: 负责人只负责存储和管理备忘录对象,不应该修改备忘录对象的内容。 负责人不应该持有备忘录对象的引用,只应该持有备忘录对象的副本。
- 发起人创建和恢复备忘录: 只有发起人才能创建备忘录对象,并且只有发起人才能从备忘录对象恢复状态。 可以使用内部类来实现备忘录类,限制备忘录类的访问权限。
7. 总结
备忘录模式是一种行为型设计模式,它通过将对象的状态封装到独立的备忘录对象中,实现了在不破坏封装性的前提下保存和恢复对象状态的功能。 这种模式特别适用于需要实现撤销/重做、版本控制、事务回滚等功能的场景。
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自徍正的随笔Blog







