备忘录模式(Memento Pattern)详解
什么是备忘录模式
备忘录模式是一种行为型设计模式,它允许在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态。
备忘录模式解决的问题
备忘录模式主要解决以下问题:
- 状态保存与恢复:需要保存对象在某一时刻的状态,以便在将来的某个时候恢复到该状态
- 封装性保护:在保存和恢复状态的同时,不破坏对象的封装性
- 状态管理:避免将对象的状态暴露给其他对象
- 撤销操作:实现撤销(Undo)和重做(Redo)功能
- 历史记录:记录对象的历史状态,以便回溯
备忘录模式的好处
- 状态封装:将对象的状态封装在备忘录中,不暴露给其他对象
- 状态管理:集中管理对象的状态,避免状态散落在代码各处
- 撤销/重做:轻松实现撤销和重做功能
- 简化代码:将状态保存和恢复的逻辑与业务逻辑分离
- 符合设计原则:遵循单一职责原则和封装原则
备忘录模式的结构
备忘录模式包含以下几个角色:
- 原发器(Originator):创建一个备忘录,记录当前状态;使用备忘录恢复状态
- 备忘录(Memento):存储原发器的内部状态
- 管理者(Caretaker):负责保存备忘录,不操作或检查备忘录的内容
各语言实现
C++ 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| #include <iostream> #include <string> #include <vector>
class Memento { private: std::string state; friend class Originator;
Memento(const std::string& s) : state(s) {}
std::string getState() const { return state; }
public: std::string getStateInfo() const { return "Memento状态: " + state; } };
class Originator { private: std::string state;
public: void setState(const std::string& s) { state = s; std::cout << "设置状态: " << state << std::endl; }
std::string getState() const { return state; }
Memento createMemento() { return Memento(state); }
void restoreMemento(const Memento& m) { state = m.getState(); std::cout << "恢复状态: " << state << std::endl; } };
class Caretaker { private: std::vector<Memento> mementos;
public: void addMemento(const Memento& m) { mementos.push_back(m); std::cout << "保存状态" << std::endl; }
Memento getMemento(int index) { if (index >= 0 && index < mementos.size()) { return mementos[index]; } throw std::out_of_range("索引超出范围"); }
size_t getMementoCount() const { return mementos.size(); } };
int main() { Originator originator; Caretaker caretaker;
originator.setState("状态1"); caretaker.addMemento(originator.createMemento());
originator.setState("状态2"); caretaker.addMemento(originator.createMemento());
originator.setState("状态3"); std::cout << "当前状态: " << originator.getState() << std::endl;
std::cout << "\n恢复到状态1:" << std::endl; originator.restoreMemento(caretaker.getMemento(0));
std::cout << "\n恢复到状态2:" << std::endl; originator.restoreMemento(caretaker.getMemento(1));
return 0; }
|
Java 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| import java.util.ArrayList; import java.util.List;
class Memento { private String state;
Memento(String state) { this.state = state; }
String getState() { return state; }
public String getStateInfo() { return "Memento状态: " + state; } }
class Originator { private String state;
public void setState(String state) { this.state = state; System.out.println("设置状态: " + state); }
public String getState() { return state; }
public Memento createMemento() { return new Memento(state); }
public void restoreMemento(Memento memento) { this.state = memento.getState(); System.out.println("恢复状态: " + state); } }
class Caretaker { private List<Memento> mementos = new ArrayList<>();
public void addMemento(Memento memento) { mementos.add(memento); System.out.println("保存状态"); }
public Memento getMemento(int index) { if (index >= 0 && index < mementos.size()) { return mementos.get(index); } throw new IndexOutOfBoundsException("索引超出范围"); }
public int getMementoCount() { return mementos.size(); } }
public class MementoPatternDemo { public static void main(String[] args) { Originator originator = new Originator(); Caretaker caretaker = new Caretaker();
originator.setState("状态1"); caretaker.addMemento(originator.createMemento());
originator.setState("状态2"); caretaker.addMemento(originator.createMemento());
originator.setState("状态3"); System.out.println("当前状态: " + originator.getState());
System.out.println("\n恢复到状态1:"); originator.restoreMemento(caretaker.getMemento(0));
System.out.println("\n恢复到状态2:"); originator.restoreMemento(caretaker.getMemento(1)); } }
|
Python 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| class Memento: def __init__(self, state): self._state = state def get_state(self): """只允许 Originator 访问""" return self._state def get_state_info(self): """提供公开的状态信息""" return f"Memento状态: {self._state}"
class Originator: def __init__(self): self._state = "" def set_state(self, state): self._state = state print(f"设置状态: {state}") def get_state(self): return self._state def create_memento(self): """创建备忘录""" return Memento(self._state) def restore_memento(self, memento): """从备忘录恢复状态""" self._state = memento.get_state() print(f"恢复状态: {self._state}")
class Caretaker: def __init__(self): self._mementos = [] def add_memento(self, memento): self._mementos.append(memento) print("保存状态") def get_memento(self, index): if 0 <= index < len(self._mementos): return self._mementos[index] raise IndexError("索引超出范围") def get_memento_count(self): return len(self._mementos)
if __name__ == "__main__": originator = Originator() caretaker = Caretaker() originator.set_state("状态1") caretaker.add_memento(originator.create_memento()) originator.set_state("状态2") caretaker.add_memento(originator.create_memento()) originator.set_state("状态3") print(f"当前状态: {originator.get_state()}") print("\n恢复到状态1:") originator.restore_memento(caretaker.get_memento(0)) print("\n恢复到状态2:") originator.restore_memento(caretaker.get_memento(1))
|
C# 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| using System; using System.Collections.Generic;
class Memento { private string state;
internal Memento(string state) { this.state = state; }
internal string GetState() { return state; }
public string GetStateInfo() { return $"Memento状态: {state}"; } }
class Originator { private string state;
public void SetState(string state) { this.state = state; Console.WriteLine($"设置状态: {state}"); }
public string GetState() { return state; }
public Memento CreateMemento() { return new Memento(state); }
public void RestoreMemento(Memento memento) { this.state = memento.GetState(); Console.WriteLine($"恢复状态: {state}"); } }
class Caretaker { private List<Memento> mementos = new List<Memento>();
public void AddMemento(Memento memento) { mementos.Add(memento); Console.WriteLine("保存状态"); }
public Memento GetMemento(int index) { if (index >= 0 && index < mementos.Count) { return mementos[index]; } throw new IndexOutOfRangeException("索引超出范围"); }
public int GetMementoCount() { return mementos.Count; } }
class Program { static void Main(string[] args) { Originator originator = new Originator(); Caretaker caretaker = new Caretaker();
originator.SetState("状态1"); caretaker.AddMemento(originator.CreateMemento());
originator.SetState("状态2"); caretaker.AddMemento(originator.CreateMemento());
originator.SetState("状态3"); Console.WriteLine($"当前状态: {originator.GetState()}");
Console.WriteLine("\n恢复到状态1:"); originator.RestoreMemento(caretaker.GetMemento(0));
Console.WriteLine("\n恢复到状态2:"); originator.RestoreMemento(caretaker.GetMemento(1)); } }
|
备忘录模式的适用场景
备忘录模式适用于以下情况:
- 需要撤销/重做功能:如文本编辑器、图形编辑器等
- 需要保存和恢复状态:如游戏存档、应用程序配置等
- 需要历史记录:如事务处理、日志系统等
- 需要状态回滚:如数据库事务、操作回滚等
- 需要保护封装性:在保存和恢复状态的同时,不破坏对象的封装性
实际应用场景
- 文本编辑器:保存文档的历史版本,支持撤销和重做
- 图形编辑器:保存绘图的历史状态,支持撤销和重做
- 游戏:保存游戏进度,支持存档和读档
- 配置管理:保存应用程序的配置状态,支持配置回滚
- 数据库事务:保存事务的状态,支持提交和回滚
- 表单编辑器:保存表单的编辑状态,支持撤销操作
备忘录模式的变体
- 增量备忘录:只记录状态的变化,而不是完整状态,减少内存使用
- 多状态备忘录:同时保存多个属性的状态
- 版本控制:保存对象的多个版本,支持版本切换
- 快照模式:定期创建对象的快照,用于恢复
注意事项
- 内存使用:如果对象的状态很大,保存多个备忘录可能会占用大量内存
- 序列化:如果需要持久化备忘录,需要考虑序列化问题
- 线程安全:在多线程环境下,需要考虑线程安全问题
- 封装性:确保备忘录的状态不被外部修改
- 性能:频繁创建和恢复备忘录可能会影响性能
备忘录模式与其他模式的结合
- 命令模式:命令模式可以使用备忘录模式实现撤销功能
- 状态模式:状态模式可以使用备忘录模式保存状态
- 原型模式:原型模式可以用于创建备忘录的深拷贝
总结
备忘录模式是一种非常实用的设计模式,它通过将对象的状态封装在备忘录中,实现了状态的保存和恢复,同时保护了对象的封装性。备忘录模式不仅可以用于实现撤销和重做功能,还可以用于状态管理、历史记录等场景。
在实际开发中,当需要保存对象的状态以便将来恢复时,备忘录模式是一个很好的解决方案。通过合理的设计,可以在不破坏封装性的前提下,实现灵活的状态管理。