0131_备忘录模式(Memento)
备忘录模式(Memento)
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后可以将该对象恢复到原先保存的状态。
UML 图

优点
- 封装性好:不暴露对象的实现细节,保持对象的封装性
- 状态恢复简单:可以轻松实现撤销/重做功能
- 状态管理集中:将状态保存和恢复的逻辑与业务逻辑分离
- 易于扩展:支持保存多个历史状态
- 符合单一职责:将状态保存的职责分离到单独的类中
缺点
- 资源消耗:如果需要保存大量状态或大对象,会消耗较多内存
- 性能开销:频繁创建和恢复备忘录可能影响性能
- 实现复杂度:需要维护备忘录的生命周期
- 可能暴露内部结构:如果设计不当,可能间接暴露对象的内部实现
代码示例
以人类状态管理系统为例:
1. 备忘录类 (Memento)
// 人类状态备忘录
public class HumanMemento {
private final String name;
private final int age;
private final double weight;
private final String healthStatus;
private final List<String> memories;
private final Date timestamp;
public HumanMemento(String name, int age, double weight,
String healthStatus, List<String> memories) {
this.name = name;
this.age = age;
this.weight = weight;
this.healthStatus = healthStatus;
this.memories = new ArrayList<>(memories); // 深拷贝
this.timestamp = new Date();
}
// Getter方法
public String getName() { return name; }
public int getAge() { return age; }
public double getWeight() { return weight; }
public String getHealthStatus() { return healthStatus; }
public List<String> getMemories() { return new ArrayList<>(memories); }
public Date getTimestamp() { return timestamp; }
@Override
public String toString() {
return String.format("状态快照[时间: %s, 姓名: %s, 年龄: %d, 体重: %.1fkg, 健康: %s]",
timestamp, name, age, weight, healthStatus);
}
}
2. 原发器类 (Originator)
// 人类 - 原发器
public class Human {
private String name;
private int age;
private double weight;
private String healthStatus;
private List<String> memories;
public Human(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight;
this.healthStatus = "健康";
this.memories = new ArrayList<>();
addMemory("出生");
}
// 创建备忘录
public HumanMemento createMemento() {
return new HumanMemento(name, age, weight, healthStatus, memories);
}
// 从备忘录恢复
public void restoreFromMemento(HumanMemento memento) {
this.name = memento.getName();
this.age = memento.getAge();
this.weight = memento.getWeight();
this.healthStatus = memento.getHealthStatus();
this.memories = memento.getMemories();
}
// 业务方法
public void growOlder() {
age++;
weight += 0.5;
addMemory("过生日,现在" + age + "岁了");
}
public void exercise() {
weight -= 1.0;
healthStatus = "非常健康";
addMemory("锻炼身体");
}
public void getSick() {
healthStatus = "生病";
weight -= 0.5;
addMemory("生病了");
}
public void recover() {
healthStatus = "康复中";
addMemory("逐渐康复");
}
public void addMemory(String memory) {
memories.add(memory + " - " + new Date());
}
public void displayStatus() {
System.out.println("=== 当前状态 ===");
System.out.println("姓名: " + name);
System.out.println("年龄: " + age + "岁");
System.out.println("体重: " + weight + "kg");
System.out.println("健康状况: " + healthStatus);
System.out.println("最近记忆: " +
(memories.isEmpty() ? "无" : memories.get(memories.size() - 1)));
System.out.println("总记忆数量: " + memories.size());
System.out.println("================\n");
}
// Getter方法
public String getName() { return name; }
public int getAge() { return age; }
public double getWeight() { return weight; }
public String getHealthStatus() { return healthStatus; }
public List<String> getMemories() { return new ArrayList<>(memories); }
}
3. 负责人类 (Caretaker)
// 状态管理器 - 负责人
public class HumanStateManager {
private final List<HumanMemento> mementos = new ArrayList<>();
private final Human human;
public HumanStateManager(Human human) {
this.human = human;
}
// 保存状态
public void saveState() {
HumanMemento memento = human.createMemento();
mementos.add(memento);
System.out.println("✅ 已保存状态: " + memento);
}
// 恢复到指定状态
public void restoreState(int index) {
if (index < 0 || index >= mementos.size()) {
System.out.println("❌ 无效的状态索引");
return;
}
HumanMemento memento = mementos.get(index);
human.restoreFromMemento(memento);
System.out.println("↩️ 已恢复到状态: " + memento);
}
// 撤销到上一个状态
public void undo() {
if (mementos.size() < 2) {
System.out.println("❌ 没有足够的历史状态可撤销");
return;
}
HumanMemento memento = mementos.get(mementos.size() - 2);
human.restoreFromMemento(memento);
mementos.remove(mementos.size() - 1); // 移除当前状态
System.out.println("↩️ 已撤销到状态: " + memento);
}
// 显示所有保存的状态
public void showHistory() {
System.out.println("=== 状态历史记录 ===");
if (mementos.isEmpty()) {
System.out.println("暂无历史记录");
} else {
for (int i = 0; i < mementos.size(); i++) {
System.out.println(i + ": " + mementos.get(i));
}
}
System.out.println("===================\n");
}
public int getHistorySize() {
return mementos.size();
}
}
4. 客户端代码
public class MementoPatternDemo {
public static void main(String[] args) {
System.out.println("=== 备忘录模式演示 - 人类状态管理系统 ===\n");
// 创建人类对象
Human person = new Human("张三", 20, 65.0);
HumanStateManager manager = new HumanStateManager(person);
// 初始状态
System.out.println("初始状态:");
person.displayStatus();
manager.saveState();
// 模拟人生变化
System.out.println("一年后...");
person.growOlder();
person.exercise();
person.displayStatus();
manager.saveState();
System.out.println("又过了一年...");
person.growOlder();
person.getSick();
person.displayStatus();
manager.saveState();
System.out.println("康复期...");
person.recover();
person.addMemory("去医院检查");
person.displayStatus();
manager.saveState();
// 显示历史记录
manager.showHistory();
// 测试撤销功能
System.out.println("测试撤销功能:");
manager.undo();
person.displayStatus();
// 恢复到特定状态
System.out.println("恢复到第1个保存的状态:");
manager.restoreState(1);
person.displayStatus();
// 继续添加新状态
System.out.println("添加新经历...");
person.addMemory("学习新技能");
person.exercise();
person.displayStatus();
manager.saveState();
// 最终历史记录
manager.showHistory();
System.out.println("=== 演示完成 ===");
}
}
在Spring的应用
在Spring框架中,备忘录模式的应用体现在:
- HTTP Session管理:Spring Session可以保存和恢复用户的会话状态
- 事务管理:Spring的事务管理器在事务回滚时使用类似备忘录的模式恢复数据状态
- 表单处理:Spring MVC的表单标签库可以保存和恢复表单状态
- 缓存机制:Spring Cache可以保存方法调用结果,并在需要时恢复
- 状态机:Spring State Machine使用备忘录模式管理状态历史
总结
备忘录模式通过将对象状态外部化,实现了状态保存和恢复的功能,同时保持了对象的封装性。在人类状态管理系统的示例中,我们可以看到:
- Human类作为原发器,负责创建和恢复备忘录
- HumanMemento类封装了人类的状态信息,提供了状态的快照
- HumanStateManager类作为负责人,管理备忘录的存储和检索
这种模式特别适用于需要实现撤销/重做功能、状态历史记录或系统快照的场景。通过备忘录模式,我们可以轻松地回溯到对象的任意历史状态,为复杂的业务流程提供了强大的状态管理能力。

浙公网安备 33010602011771号