备忘录模式C++

备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不暴露对象内部状态的情况下,捕获并保存对象的内部状态,以便在将来需要时恢复该状态。这种模式实现了对象状态的快照保存与恢复,常用于撤销操作、历史记录等场景。

备忘录模式的核心角色

  1. Originator(发起人):创建一个备忘录,用于记录自身当前状态;也可使用备忘录恢复状态
  2. Memento(备忘录):存储发起人的内部状态,对发起人以外的对象隐藏状态细节
  3. Caretaker(负责人):负责保存备忘录,但不能对备忘录的内容进行操作或检查

C++实现示例

以下以"文本编辑器的撤销功能"为例实现备忘录模式,支持保存文本的历史状态并在需要时恢复:

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

// 备忘录类:存储文本状态(对外部隐藏实现细节)
class TextMemento {
private:
    // 只有发起人可以访问备忘录的状态
    friend class TextEditor;
    
    std::string content;  // 文本内容
    int cursorPos;        // 光标位置
    
    // 私有构造函数,防止外部创建
    TextMemento(std::string cont, int pos) 
        : content(std::move(cont)), cursorPos(pos) {}
};

// 发起人:文本编辑器
class TextEditor {
private:
    std::string content;  // 当前文本内容
    int cursorPos;        // 当前光标位置

public:
    TextEditor() : cursorPos(0) {}

    // 输入文本
    void type(const std::string& text) {
        content.insert(cursorPos, text);
        cursorPos += text.length();
    }

    // 移动光标
    void moveCursor(int pos) {
        if (pos >= 0 && pos <= static_cast<int>(content.length())) {
            cursorPos = pos;
        }
    }

    // 创建备忘录(保存当前状态)
    std::unique_ptr<TextMemento> save() const {
        return std::make_unique<TextMemento>(content, cursorPos);
    }

    // 从备忘录恢复状态
    void restore(const TextMemento* memento) {
        if (memento) {
            content = memento->content;
            cursorPos = memento->cursorPos;
        }
    }

    // 显示当前状态
    void display() const {
        std::cout << "文本内容: " << content << std::endl;
        std::cout << "光标位置: " << cursorPos << std::endl;
        // 显示光标位置指示
        std::cout << "          " << std::string(cursorPos, ' ') << "^" << std::endl;
    }

    // 获取当前内容长度(用于测试)
    size_t getContentLength() const {
        return content.length();
    }
};

// 负责人:历史记录管理器
class HistoryManager {
private:
    std::vector<std::unique_ptr<TextMemento>> mementos;  // 存储备忘录
    int currentIndex;  // 当前状态索引

public:
    HistoryManager() : currentIndex(-1) {}

    // 保存新状态
    void saveState(std::unique_ptr<TextMemento> memento) {
        // 清除当前状态之后的历史(如果有)
        if (currentIndex < static_cast<int>(mementos.size()) - 1) {
            mementos.erase(mementos.begin() + currentIndex + 1, mementos.end());
        }
        // 添加新状态
        mementos.push_back(std::move(memento));
        currentIndex = mementos.size() - 1;
    }

    // 撤销操作(恢复到上一个状态)
    const TextMemento* undo() {
        if (currentIndex > 0) {
            currentIndex--;
            return mementos[currentIndex].get();
        }
        std::cout << "已到达最早状态,无法继续撤销" << std::endl;
        return nullptr;
    }

    // 重做操作(恢复到下一个状态)
    const TextMemento* redo() {
        if (currentIndex < static_cast<int>(mementos.size()) - 1) {
            currentIndex++;
            return mementos[currentIndex].get();
        }
        std::cout << "已到达最新状态,无法继续重做" << std::endl;
        return nullptr;
    }

    // 获取历史记录数量
    size_t getHistoryCount() const {
        return mementos.size();
    }
};

// 客户端代码
int main() {
    // 创建文本编辑器和历史管理器
    TextEditor editor;
    HistoryManager history;

    // 第一次操作
    std::cout << "=== 第一次输入 ===" << std::endl;
    editor.type("Hello, ");
    editor.display();
    history.saveState(editor.save());  // 保存状态1

    // 第二次操作
    std::cout << "\n=== 第二次输入 ===" << std::endl;
    editor.type("World!");
    editor.display();
    history.saveState(editor.save());  // 保存状态2

    // 第三次操作
    std::cout << "\n=== 第三次输入 ===" << std::endl;
    editor.moveCursor(7);  // 移动光标到逗号后
    editor.type("Beautiful ");
    editor.display();
    history.saveState(editor.save());  // 保存状态3

    // 撤销一次
    std::cout << "\n=== 第一次撤销 ===" << std::endl;
    editor.restore(history.undo());
    editor.display();

    // 再撤销一次
    std::cout << "\n=== 第二次撤销 ===" << std::endl;
    editor.restore(history.undo());
    editor.display();

    // 重做一次
    std::cout << "\n=== 第一次重做 ===" << std::endl;
    editor.restore(history.redo());
    editor.display();

    return 0;
}

代码解析

  1. 备忘录(TextMemento

    • 私有构造函数确保只有发起人(TextEditor)可以创建它
    • 通过friend关键字让发起人访问其内部状态(contentcursorPos
    • 对负责人和客户端隐藏状态细节,保证封装性
  2. 发起人(TextEditor

    • 维护文本编辑器的当前状态(内容和光标位置)
    • 提供save()方法创建备忘录,捕获当前状态
    • 提供restore()方法从备忘录恢复状态
    • 包含文本编辑的核心功能(输入、移动光标等)
  3. 负责人(HistoryManager

    • 管理备忘录的存储和检索,不直接操作备忘录内容
    • 支持撤销(undo())和重做(redo())功能
    • 维护当前状态索引,正确管理历史记录的顺序
  4. 工作流程

    • 编辑器每完成一次操作,通过save()创建备忘录并交由负责人保存
    • 需要撤销时,负责人返回上一个备忘录,编辑器用其恢复状态
    • 重做功能则恢复到撤销前的状态,实现了灵活的状态回溯

备忘录模式的优缺点

优点

  • 实现了状态的封装与恢复,发起人无需暴露内部细节
  • 客户端可以通过负责人灵活地管理历史状态(撤销/重做)
  • 负责人与发起人解耦,两者各司其职(状态管理与业务逻辑)
  • 便于保存和恢复对象的任意历史状态

缺点

  • 如果对象状态较大或频繁保存,会消耗较多内存
  • 备忘录可能包含大量状态数据,复制成本较高
  • 负责人需要管理大量备忘录,增加了系统复杂度

适用场景

  • 当需要保存和恢复对象的历史状态时(如撤销操作)
  • 当不希望暴露对象的内部状态,却需要捕获和恢复状态时
  • 当需要维护对象的历史记录,以便后续分析或回滚时

常见应用:

  • 文本编辑器的撤销/重做功能
  • 数据库事务的提交与回滚
  • 游戏中的存档与读档功能
  • 图形编辑软件的历史记录功能

备忘录模式的关键是平衡封装性和灵活性:发起人保持对状态的控制,备忘录隐藏实现细节,负责人提供便捷的状态管理接口,三者协作实现安全高效的状态快照机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值