备忘录模式 (Memento Pattern)
什么是备忘录模式?
备忘录模式是一种行为型设计模式,它允许你在不违反封装原则的前提下保存和恢复对象的内部状态。
简单来说:备忘录模式就是"存档",可以保存对象的状态,之后可以恢复。
生活中的例子
想象一下:
- 游戏存档:保存游戏进度,之后可以恢复
- 文档撤销:撤销操作,恢复到之前的状态
- 版本控制:Git提交,可以恢复到之前的版本
为什么需要备忘录模式?
传统方式的问题
java
// 直接保存状态
Object state = object.getState();
object.setState(state);
问题:
- 破坏封装:需要暴露对象的内部状态
- 无法撤销:无法撤销到之前的状态
- 难以管理:难以管理多个状态
备忘录模式的优势
java
// 使用备忘录
Memento memento = object.save();
object.restore(memento);
优势:
- 保持封装:不暴露对象的内部状态
- 可以撤销:可以撤销到之前的状态
- 易于管理:易于管理多个状态
备忘录模式的结构
┌─────────────────────┐
│ Memento │ 备忘录
├─────────────────────┤
│ - state: Object │
│ + getState(): Object│
└─────────────────────┘
┌─────────────────────┐
│ Originator │ 发起人
├─────────────────────┤
│ - state: Object │
│ + save(): Memento │
│ + restore(): void │
└─────────────────────┘
┌─────────────────────┐
│ Caretaker │ 管理者
├─────────────────────┤
│ - mementos: List │
│ + add(): void │
│ + get(): Memento │
└─────────────────────┘
代码示例
1. 定义备忘录
java
/**
* 备忘录:保存发起人的状态
*/
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
2. 定义发起人
java
/**
* 发起人:需要保存状态的对象
*/
public class Originator {
private String state;
public void setState(String state) {
this.state = state;
System.out.println("当前状态: " + state);
}
public String getState() {
return state;
}
/**
* 创建备忘录
*/
public Memento save() {
System.out.println("保存状态: " + state);
return new Memento(state);
}
/**
* 恢复备忘录
*/
public void restore(Memento memento) {
this.state = memento.getState();
System.out.println("恢复状态: " + state);
}
}
3. 定义管理者
java
/**
* 管理者:管理备忘录
*/
public class Caretaker {
private List<Memento> mementos = new ArrayList<>();
/**
* 添加备忘录
*/
public void add(Memento memento) {
mementos.add(memento);
System.out.println("备忘录已保存,当前共有 " + mementos.size() + " 个备忘录");
}
/**
* 获取备忘录
*/
public Memento get(int index) {
return mementos.get(index);
}
/**
* 获取备忘录数量
*/
public int size() {
return mementos.size();
}
}
4. 使用备忘录
java
/**
* 备忘录模式测试类
* 演示如何使用备忘录模式保存和恢复状态
*/
public class MementoTest {
public static void main(String[] args) {
System.out.println("=== 备忘录模式测试 ===\n");
// 创建发起人和管理者
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
// 保存状态
System.out.println("--- 保存状态 ---");
originator.setState("状态1");
caretaker.add(originator.save());
originator.setState("状态2");
caretaker.add(originator.save());
originator.setState("状态3");
caretaker.add(originator.save());
System.out.println("\n--- 恢复状态 ---");
System.out.println("当前状态: " + originator.getState());
// 恢复到上一个状态
System.out.println("\n恢复到上一个状态:");
originator.restore(caretaker.get(caretaker.size() - 1));
// 恢复到第一个状态
System.out.println("\n恢复到第一个状态:");
originator.restore(caretaker.get(0));
// 恢复到第二个状态
System.out.println("\n恢复到第二个状态:");
originator.restore(caretaker.get(1));
System.out.println("\n=== 备忘录模式的优势 ===");
System.out.println("1. 保持封装:不暴露对象的内部状态");
System.out.println("2. 可以撤销:可以撤销到之前的状态");
System.out.println("3. 易于管理:易于管理多个状态");
System.out.println("\n=== 实际应用场景 ===");
System.out.println("1. 游戏存档:保存游戏进度");
System.out.println("2. 文档撤销:撤销操作");
System.out.println("3. 版本控制:版本控制系统");
System.out.println("4. 数据库事务:事务回滚");
System.out.println("\n=== 与命令模式的区别 ===");
System.out.println("备忘录模式:保存对象的状态");
System.out.println("命令模式:保存操作的历史");
System.out.println("两者可以结合使用,实现完整的撤销功能");
}
}
备忘录模式的优点
- 保持封装:不暴露对象的内部状态
- 可以撤销:可以撤销到之前的状态
- 易于管理:易于管理多个状态
备忘录模式的缺点
- 内存消耗:保存多个状态会消耗内存
- 性能开销:创建和恢复状态有性能开销
适用场景
- 需要撤销:需要撤销操作
- 需要保存:需要保存对象状态
- 保持封装:需要保持对象的封装性
常见应用场景
- 游戏存档:保存游戏进度
- 文档撤销:撤销操作
- 版本控制:版本控制系统
使用建议
- 需要撤销:使用备忘录模式
- 需要保存:使用备忘录模式
- 简单状态:直接保存即可
注意事项
⚠️ 备忘录模式虽然有用,但要注意:
- 不要保存太多状态,消耗内存
- 考虑使用命令模式