备忘录模式(Memento Pattern)学习笔记
编程相关书籍分享:https://blog.csdn.net/weixin_47763579/article/details/145855793
DeepSeek使用技巧pdf资料分享:https://blog.csdn.net/weixin_47763579/article/details/145884039
1. 模式定义
行为型设计模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便后续恢复对象到原先保存的状态。
2. 适用场景
✅ 需要实现撤销/重做功能
✅ 需要保存对象历史快照
✅ 需要提供系统状态回滚机制
✅ 需要隔离对象状态存储细节
✅ 需要实现事务回滚操作
3. 模式结构
4. 核心角色
角色 | 说明 |
---|---|
Originator | 原发器:需要保存状态的对象 |
Memento | 备忘录:存储原发器内部状态的对象(通常不可修改) |
Caretaker | 管理者:负责保存/恢复备忘录,但不能操作备忘录内容 |
5. 代码示例
5.1 文本编辑器撤销功能
// 备忘录类
final class TextMemento {
private final String content;
public TextMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
// 原发器类
class TextEditor {
private StringBuilder content = new StringBuilder();
public void append(String text) {
content.append(text);
}
public TextMemento save() {
return new TextMemento(content.toString());
}
public void restore(TextMemento memento) {
content = new StringBuilder(memento.getContent());
}
public void print() {
System.out.println("当前内容: " + content);
}
}
// 管理者类
class HistoryManager {
private final Stack<TextMemento> history = new Stack<>();
public void push(TextMemento memento) {
history.push(memento);
}
public TextMemento pop() {
return history.pop();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
HistoryManager history = new HistoryManager();
editor.append("Hello");
history.push(editor.save());
editor.print();
editor.append(" World");
history.push(editor.save());
editor.print();
System.out.println("执行撤销操作:");
editor.restore(history.pop());
editor.print();
}
}
/* 输出:
当前内容: Hello
当前内容: Hello World
执行撤销操作:
当前内容: Hello */
6. 模式变种
6.1 白箱 vs 黑箱实现
类型 | 实现方式 | 特点 |
---|---|---|
白箱 | Memento公开状态访问方法 | 违反封装原则,但实现简单 |
黑箱 | Memento使用内部类隐藏实现 | 保持封装性,Java常用实现方式 |
// 黑箱实现示例
class Originator {
private String state;
public IMemento save() {
return new Memento(state);
}
public void restore(IMemento m) {
this.state = ((Memento)m).getState();
}
// 内部类实现备忘录
private static class Memento implements IMemento {
private final String state;
private Memento(String state) {
this.state = state;
}
private String getState() {
return state;
}
}
}
interface IMemento {} // 标记接口
7. 优缺点分析
✔️ 优点:
- 保持对象封装边界
- 简化原发器职责
- 支持状态历史管理
- 实现撤销/恢复机制
❌ 缺点:
- 消耗内存资源(需保存多个状态副本)
- 频繁保存影响性能
- 需要合理设计备忘录存储策略
- 增加系统复杂度
8. 相关模式对比
模式 | 目的 | 关键区别 |
---|---|---|
原型模式 | 对象克隆 | 关注对象复制,备忘录关注状态保存 |
命令模式 | 操作封装 | 命令模式可存储操作,备忘录存储状态 |
状态模式 | 状态管理 | 状态模式改变行为,备忘录保存状态 |
9. 实际应用案例
- 文本/图形编辑器的撤销栈
- 数据库事务回滚机制
- 游戏存档/读档功能
- 浏览器页面历史记录
- IDE的本地历史功能
- 金融系统的交易快照
- Java序列化机制(Serializable)
10. 最佳实践建议
- 控制备忘录数量:
// 使用最大历史记录限制
class BoundedHistory {
private final Deque<Memento> stack = new ArrayDeque<>();
private final int maxSize;
public BoundedHistory(int maxSize) {
this.maxSize = maxSize;
}
public void push(Memento m) {
if (stack.size() >= maxSize) {
stack.removeFirst();
}
stack.addLast(m);
}
}
- 增量存储优化:
// 仅存储变化量
class DeltaMemento {
private final String delta;
private final long timestamp;
// ...
}
- 使用序列化实现深存储:
// 通过序列化保存对象状态
class SerializedMemento {
public static byte[] serialize(Object obj) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
return bos.toByteArray();
}
}
public static Object deserialize(byte[] data) throws Exception {
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis)) {
return ois.readObject();
}
}
}
- 结合原型模式:
class Originator implements Cloneable {
public Memento save() {
return new Memento(this.clone());
}
protected Originator clone() {
try {
return (Originator) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
🕰️ 设计原则体现:
- 单一职责原则:状态管理职责分离到备忘录
- 开闭原则:新增备忘录类型无需修改原发器
- 封装性:保护对象内部状态不被直接访问
通过备忘录模式,可以实现灵活的状态管理机制,特别适合需要支持撤销/重做、事务回滚等功能的场景。该模式在编辑器、游戏开发、金融系统中应用广泛,是保护对象状态完整性的经典解决方案。