备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)


定义

  • 备忘录模式是一种‌ 行为型设计模式‌,允许在不破坏对象封装性的前提下,捕获并保存对象的内部状态,并在需要时恢复该状态。它通过将对象状态封装在独立的“备忘录对象”中,实现状态的保存与恢复逻辑的解耦。

‌核心思想

  • 状态快照‌:将对象状态保存为一个不可变的快照(备忘录对象)。

  • 封装性保护‌:不直接暴露对象内部状态,而是通过备忘录类间接操作。

  • 职责分离‌:由独立的“备忘录”类存储状态,由“负责人”类管理状态历史,降低对象与状态管理的耦合。

模式结构

备忘录模式包含三个核心角色:

角色 职责
Originator 需要保存状态的对象(如文本编辑器、游戏角色),负责创建和恢复备忘录对象}。
Memento 存储 Originator 内部状态的不可变快照,仅允许 Originator 访问其数据}。
Caretaker 管理备忘录历史记录(如栈结构实现撤销/重做),不直接操作备忘录内容}。

‌主要解决的问题

  • 撤销/重做功能‌:如文本编辑器的撤销操作、游戏的存档读档。

  • 状态回滚‌:在事务处理中恢复到之前的正确状态。

  • 封装性保护‌:避免直接暴露对象内部状态,防止外部代码破坏其一致性。

代码示例

  • 以下是一个‌文本编辑器撤销功能‌的 C# 实现:

using System;

// 备忘录(Memento)
public class TextMemento
{
    public string Content { get; } // 不可变快照

    public TextMemento(string content)
    {
        Content = content;
    }
}

// 发起人(Originator)
public class TextEditor
{
    private string _content;

    public string Content
    {
        get => _content;
        set
        {
            Console.WriteLine($"修改内容为:{value}");
            _content = value;
        }
    }

    // 创建备忘录
    public TextMemento Save()
    {
        Console.WriteLine("保存当前内容到备忘录");
        return new TextMemento(_content);
    }

    // 恢复备忘录
    public void Undo(TextMemento memento)
    {
        if (memento != null)
        {
            _content = memento.Content;
            Console.WriteLine($"撤销到内容:{_content}");
        }
    }
}

// 负责人(Caretaker)
public class History
{
    private Stack<TextMemento> _history = new Stack<TextMemento>();

    public void Push(TextMemento memento) => _history.Push(memento);
    public TextMemento? Pop() => _history.Count >0 ? _history.Pop() : null;
}

// 客户端代码
class Program
{
    static void Main()
    {
        var editor = new TextEditor();
        var history = new History();

        editor.Content = "第一版内容";
        history.Push(editor.Save()); // 保存状态1

        editor.Content = "第二版内容";
        history.Push(editor.Save()); // 保存状态2

        editor.Content = "第三版内容"; // 未保存

        // 执行两次撤销
        editor.Undo(history.Pop()); // 输出:撤销到内容:第二版内容
        editor.Undo(history.Pop()); // 输出:撤销到内容:第一版内容
    }
}

输出结果‌:

修改内容为:第一版内容  
保存当前内容到备忘录  
修改内容为:第二版内容  
保存当前内容到备忘录  
修改内容为:第三版内容  
撤销到内容:第二版内容  
撤销到内容:第一版内容  

总结

优点‌:

  • 严格保护对象封装性,状态保存逻辑与业务逻辑分离。

  • 简化 Originator 类,状态管理由 Caretaker 处理。

缺点‌:

  • 频繁保存大对象可能导致内存消耗增加。

适用场景‌:

  • 需要实现撤销/重做功能(如编辑器、绘图软件)。

  • 需要生成对象状态快照(如游戏存档、事务回滚)。

posted @ 2025-04-23 14:38  刘继先  阅读(50)  评论(0)    收藏  举报