备忘录模式(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(); } }
}
🕰️ 设计原则体现:
- 单一职责原则:状态管理职责分离到备忘录
- 开闭原则:新增备忘录类型无需修改原发器
- 封装性:保护对象内部状态不被直接访问
通过备忘录模式,可以实现灵活的状态管理机制,特别适合需要支持撤销/重做、事务回滚等功能的场景。该模式在编辑器、游戏开发、金融系统中应用广泛,是保护对象状态完整性的经典解决方案。