设计模式 18
- 创建型模式(5):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型模式(7):适配器模式、桥接模式、组合模式、装饰者模式、外观模式、享元模式、代理模式
- 行为型模式(11):责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
备忘录模式(Memento Pattern)
1 定义
备忘录模式的核心思想是将对象的状态保存在一个备忘录对象中,并允许在未来的某个时刻恢复该状态。备忘录模式保证了状态的封装性,外部对象无法直接访问备忘录中的内容,从而保护了原发器对象的内部细节。
2 结构
备忘录模式包含以下角色:
- 原发器(Originator): 创建备忘录以记录当前状态,并可以使用备忘录恢复先前状态。
- 备忘录(Memento): 存储原发器的内部状态,备忘录对外部是不可见的,只能由原发器访问。
- 负责人(Caretaker): 负责存储和管理备忘录,但不会修改或检查备忘录的内容。
UML 类图
+---------------------------------------+      
|  Originator                           |       
+---------------------------------------+     
| - state: String                       |   
| + CreateMemento(): Memento            |  
| + SetMemento(memento: Memento): void  |  
+---------------------------------------+     
        |                          
        |                          
+-----------------------+           +-----------------------+
|   Memento             |           |   Caretaker           |
+-----------------------+           +-----------------------+
| - state: String       |           | - memento: Memento    |
| + GetState(): String  |           +-----------------------+
+-----------------------+     
3 示例代码
假设我们要实现一个简单的文本编辑器,它能够保存文本的状态,并在需要时撤销或恢复状态。
原发器
// 原发器类
public class TextEditor
{
    private string _text;
    public void SetText(string text)
    {
        _text = text;
    }
    public string GetText()
    {
        return _text;
    }
    public Memento CreateMemento()
    {
        return new Memento(_text);
    }
    public void RestoreMemento(Memento memento)
    {
        _text = memento.GetState();
    }
}
备忘录
// 备忘录类
public class Memento
{
    private readonly string _state;
    public Memento(string state)
    {
        _state = state;
    }
    public string GetState()
    {
        return _state;
    }
}
负责人
// 负责人类
public class Caretaker
{
    private readonly Stack<Memento> _mementos = new Stack<Memento>();
    public void SaveMemento(Memento memento)
    {
        _mementos.Push(memento);
    }
    public Memento GetMemento()
    {
        if (_mementos.Count > 0)
        {
            return _mementos.Pop();
        }
        return null;
    }
}
客户端代码
class Program
{
    static void Main(string[] args)
    {
        TextEditor editor = new TextEditor();
        Caretaker caretaker = new Caretaker();
        editor.SetText("Version 1");
        caretaker.SaveMemento(editor.CreateMemento());
        editor.SetText("Version 2");
        caretaker.SaveMemento(editor.CreateMemento());
        editor.SetText("Version 3");
        Console.WriteLine("Current Text: " + editor.GetText());
        editor.RestoreMemento(caretaker.GetMemento());
        Console.WriteLine("Restored Text: " + editor.GetText());
        editor.RestoreMemento(caretaker.GetMemento());
        Console.WriteLine("Restored Text: " + editor.GetText());
    }
}
运行结果
Current Text: Version 3
Restored Text: Version 2
Restored Text: Version 1
在这个例子中,TextEditor 是原发器,负责创建和恢复文本的状态;Memento 是备忘录,保存文本的状态;Caretaker 是负责人,管理备忘录的存储和恢复。在运行过程中,我们保存了多个文本状态,并通过恢复操作撤销了修改,返回到之前的状态。
6 特点
- 优点: - 封装性: 备忘录模式保证了原发器状态的封装性,外部对象无法直接访问备忘录的内容。 
- 状态恢复: 允许对象恢复到之前的状态,提供了实现“撤销/恢复”功能的简单方法。 
- 简化复杂性: 通过将状态的存储和恢复职责分离到不同的类中,简化了复杂系统的管理。 
 
- 缺点: - 开销大: 如果原发器的状态占用大量资源(如内存),备忘录模式可能会导致开销较大,尤其是在频繁保存和恢复状态时。 
- 管理复杂: 如果备忘录数量众多,管理这些备忘录可能变得复杂,尤其是在涉及多线程操作时。 
 
7 适用场景
- 实现撤销/恢复功能: 当需要实现“撤销/恢复”操作时,备忘录模式非常适用。
- 需要记录历史状态: 在需要保存和恢复对象的多个历史状态的场景中,可以使用备忘录模式。
- 简化复杂对象的状态管理: 在复杂对象状态变化频繁且需要保证状态一致性的情况下,备忘录模式提供了一种有效的管理方式。
8 总结
备忘录模式通过保存对象的状态,提供了恢复该状态的机制。它通过封装状态,确保了对象内部细节的保护,同时又允许状态的恢复。该模式非常适合用于实现“撤销/恢复”功能,并在需要管理复杂状态变更的场景中提供了很好的解决方案。