C++实现设计模式---备忘录模式 (Memento)

发布于:2025-02-10 ⋅ 阅读:(94) ⋅ 点赞:(0)

备忘录模式 (Memento)

备忘录模式 是一种行为型设计模式,它允许在不破坏封装的前提下,捕获和恢复对象的内部状态。通过备忘录模式,可以在程序运行时存储某个对象的历史状态,并在需要时恢复。


意图

  • 提供一种方法,在不破坏对象封装性的前提下捕获和恢复其内部状态。
  • 通过备忘录存储对象的历史状态,便于实现撤销、重做功能。

使用场景

  1. 需要保存对象的历史状态
    • 如文本编辑器中的撤销、恢复功能。
  2. 需要在程序运行时回滚对象状态
    • 如游戏中存储和恢复玩家进度。
  3. 希望避免暴露对象的实现细节
    • 通过备忘录隐藏对象的内部状态。

参与者角色

  1. 发起人 (Originator)
    • 定义一个创建和恢复备忘录的接口,负责存储对象的内部状态。
  2. 备忘录 (Memento)
    • 存储发起人对象的内部状态。
    • 对发起人以外的其他对象是不可变的。
  3. 管理者 (Caretaker)
    • 负责保存和恢复备忘录,但无法访问备忘录的内容。

示例代码

以下代码展示了备忘录模式的实现,用于模拟一个文本编辑器的撤销和恢复功能。

#include <iostream>
#include <string>
#include <vector>
#include <memory>

// 备忘录类:存储文本状态
class Memento {
private:
    std::string state;

public:
    explicit Memento(const std::string& state) : state(state) {}

    std::string getState() const {
        return state;
    }
};

// 发起人类:文本编辑器
class TextEditor {
private:
    std::string text;

public:
    void appendText(const std::string& newText) {
        text += newText;
    }

    void setText(const std::string& newText) {
        text = newText;
    }

    std::string getText() const {
        return text;
    }

    // 创建备忘录
    std::unique_ptr<Memento> save() const {
        return std::make_unique<Memento>(text);
    }

    // 恢复状态
    void restore(const Memento& memento) {
        text = memento.getState();
    }
};

// 管理者类:管理备忘录
class Caretaker {
private:
    std::vector<std::unique_ptr<Memento>> history;

public:
    void save(std::unique_ptr<Memento> memento) {
        history.push_back(std::move(memento));
    }

    const Memento* undo() {
        if (!history.empty()) {
            const Memento* memento = history.back().get();
            history.pop_back();
            return memento;
        }
        return nullptr;
    }
};

// 客户端代码
int main() {
    TextEditor editor;
    Caretaker caretaker;

    editor.appendText("Hello");
    caretaker.save(editor.save()); // 保存状态

    editor.appendText(", World!");
    caretaker.save(editor.save()); // 保存状态

    editor.appendText(" Welcome to the Memento Pattern.");

    std::cout << "当前文本: " << editor.getText() << "
";

    // 撤销操作
    const Memento* memento = caretaker.undo();
    if (memento) {
        editor.restore(*memento);
        std::cout << "撤销后文本: " << editor.getText() << "
";
    }

    memento = caretaker.undo();
    if (memento) {
        editor.restore(*memento);
        std::cout << "再次撤销后文本: " << editor.getText() << "
";
    }

    return 0;
}

代码解析

1. 备忘录类 (Memento)
  • 存储发起人对象的内部状态,并提供一个方法获取状态。
  • 对其他对象不可变,只有发起人可以访问和修改它的内容。
class Memento {
private:
    std::string state;

public:
    explicit Memento(const std::string& state) : state(state) {}

    std::string getState() const {
        return state;
    }
};
2. 发起人类 (TextEditor)
  • 负责创建和恢复备忘录。
  • 提供 save 方法创建备忘录和 restore 方法恢复备忘录中的状态。
class TextEditor {
private:
    std::string text;

public:
    void appendText(const std::string& newText) {
        text += newText;
    }

    std::unique_ptr<Memento> save() const {
        return std::make_unique<Memento>(text);
    }

    void restore(const Memento& memento) {
        text = memento.getState();
    }
};
3. 管理者类 (Caretaker)
  • 保存和管理备忘录对象的历史。
  • 提供 save 方法保存备忘录,和 undo 方法实现状态回滚。
class Caretaker {
private:
    std::vector<std::unique_ptr<Memento>> history;

public:
    void save(std::unique_ptr<Memento> memento) {
        history.push_back(std::move(memento));
    }

    const Memento* undo() {
        if (!history.empty()) {
            const Memento* memento = history.back().get();
            history.pop_back();
            return memento;
        }
        return nullptr;
    }
};
4. 客户端代码
  • 客户端通过 TextEditor 创建和恢复状态,Caretaker 保存备忘录。

优缺点

优点
  1. 封装性
    • 备忘录对象对其他类是不可变的,保护了发起人的内部状态。
  2. 简化撤销/恢复操作
    • 通过备忘录存储历史状态,可以轻松实现撤销和恢复功能。
  3. 符合单一职责原则
    • 发起人和管理者各自负责不同的功能。
缺点
  1. 内存开销
    • 每次保存状态都会创建一个备忘录对象,可能占用较多内存。
  2. 实现复杂性
    • 需要额外的类来管理和存储备忘录。

适用场景

  1. 需要存储对象的历史状态
    • 如撤销功能、版本控制等场景。
  2. 需要恢复对象状态
    • 如游戏进度存储和恢复。
  3. 希望对象状态的存储和恢复对外透明
    • 通过备忘录隐藏内部实现细节。

总结

备忘录模式通过存储对象的历史状态,实现了状态的保存和恢复功能。它特别适用于需要撤销操作或恢复特定状态的场景。虽然会增加内存开销,但其封装性和操作的便利性使其在许多应用中非常有用。


网站公告

今日签到

点亮在社区的每一天
去签到