备忘录模式(Memento Pattern)是一种行为型设计模式,其核心思想是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。其本质是通过封装状态对象实现历史状态的管理,避免直接暴露对象内部细节。
@startuml
class Originator {
- state: Object
+ createMemento(): Memento
+ restore(Memento m): void
}
class Memento {
- state: Object
+ Memento(state: Object)
- getState(): Object
}
class Caretaker {
- memento: Memento
+ setMemento(m: Memento): void
+ getMemento(): Memento
}
Originator "1" -- "1" Memento : 创建
Caretaker "1" -- "1" Memento : 管理
@enduml
Originator(原发器)
createMemento()
(创建备忘录)、restore(Memento m)
(恢复状态)Memento(备忘录)
Caretaker(管理者)
java
public class Role {
private int hp;
private int attack;
private int defense;
// 创建备忘录
public RoleMemento createMemento() {
return new RoleMemento(hp, attack, defense);
}
// 恢复状态
public void restoreFromMemento(RoleMemento memento) {
this.hp = memento.getHp();
this.attack = memento.getAttack();
this.defense = memento.getDefense();
}
// 状态变更方法
public void takeDamage(int damage) {
hp = Math.max(0, hp - damage);
}
// 省略getter/setter和构造方法
}
java
public class Role {
// 静态内部类作为备忘录
public static class RoleMemento {
private final int hp;
private final int attack;
private final int defense;
private RoleMemento(int hp, int attack, int defense) {
this.hp = hp;
this.attack = attack;
this.defense = defense;
}
// 包内可见的访问方法
int getHp() { return hp; }
int getAttack() { return attack; }
int getDefense() { return defense; }
}
}
java
public class GameCaretaker {
private final Stack mementoStack = new Stack<>();
public void saveState(Role role) {
mementoStack.push(role.createMemento());
}
public void undoState(Role role) {
if (!mementoStack.isEmpty()) {
role.restoreFromMemento(mementoStack.pop());
}
}
}
java
public class TextEditor {
private String content;
public TextMemento saveStateToMemento() {
return new TextMemento(content);
}
public void restoreStateFromMemento(TextMemento memento) {
content = memento.getContent();
}
// 编辑操作
public void appendText(String text) {
content += text;
}
}
public class TextEditorCaretaker {
private final List mementoList = new ArrayList<>();
public void addMemento(TextMemento memento) {
mementoList.add(memento);
}
public TextMemento getMemento(int index) {
return mementoList.get(index);
}
}
java
// 假设index为历史版本索引
editor.restoreStateFromMemento(caretaker.getMemento(index));
java
public class SerializableMemento implements Serializable {
private static final long serialVersionUID = 1L;
private final Map state;
public SerializableMemento(Map state) {
this.state = new HashMap<>(state);
}
public Map getState() {
return new HashMap<>(state);
}
}
java
public class MementoStorage {
public static void saveToFile(Memento memento, String filename) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
oos.writeObject(memento);
}
}
public static Memento loadFromFile(String filename) throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {
return (Memento) ois.readObject();
}
}
}
当满足以下条件时推荐使用:
问题场景 | 产生原因 | 解决方案 |
---|---|---|
状态修改影响备忘录 | 引用类型未深拷贝 | 使用深度克隆或不可变对象存储状态 |
管理者访问私有状态 | 备忘录接口设计不当 | 采用包可见性或内部类封装状态访问 |
历史版本爆炸 | 未控制备忘录数量 | 实现版本清理策略(如固定版本数、时间淘汰) |
序列化兼容性问题 | 备忘录类修改后反序列化失败 | 正确实现 Serializable 接口,保持 VersionUID 一致 |
clone()
方法可保存时间对象状态new Date(oldDate.getTime())
工具 / 框架 | 备忘录角色 | 状态存储方式 | 恢复机制 |
---|---|---|---|
文本编辑器 | 编辑内容对象 | 字符串快照列表 | 按索引获取历史版本 |
数据库事务 | 数据行快照 | 回滚日志 | 事务回滚操作 |
IDE 撤销功能 | 文档模型对象 | 操作日志栈 | 逆向执行操作 |
java
// 固定版本数的管理者实现
public class LimitedVersionCaretaker {
private final int maxVersions;
private final Queue mementoQueue = new LinkedList<>();
public LimitedVersionCaretaker(int maxVersions) {
this.maxVersions = maxVersions;
}
public void addMemento(Memento m) {
mementoQueue.add(m);
if (mementoQueue.size() > maxVersions) {
mementoQueue.poll(); // 移除最旧版本
}
}
}
备忘录模式通过巧妙的封装设计,在不破坏对象封装性的前提下实现了灵活的状态管理。它不仅解决了撤销操作等具体问题,更体现了 "将变化封装" 的设计思想。在 Java 开发中,合理运用备忘录模式可以显著提升系统的可维护性和用户体验,尤其是在需要历史状态管理的复杂场景中。
通过深入理解备忘录模式的核心原理,掌握 Java 中的具体实现方法,并结合实际场景进行优化,开发者可以在软件系统中实现优雅的状态管理解决方案。记住,设计模式的精髓在于灵活运用,而非生搬硬套,根据具体需求选择合适的实现方式才能发挥模式的最大价值。