跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++备忘录模式:优雅实现对象状态保存与恢复

备忘录模式用于在不破坏封装性的前提下捕获对象内部状态,通过发起人、备忘录和管理者三个角色协作,实现状态回滚和撤销功能。C++ 实现需注意内存管理,推荐使用智能指针避免泄漏。该模式适用于编辑器撤销、游戏存档及事务回滚等场景,常与命令模式配合使用。

暗影行者发布于 2026/3/26更新于 2026/10/2581 浏览
C++备忘录模式:优雅实现对象状态保存与恢复

C++备忘录模式:优雅实现对象状态保存与恢复

在开发中,我们常会遇到需要撤销操作、历史记录或状态回滚的场景。备忘录模式(Memento Pattern)正是为此而生。它允许在不破坏封装性的前提下捕获对象的内部状态,以便后续恢复。今天我们就来聊聊如何在 C++ 中落地这一模式,顺便避避坑。

核心角色解析

理解备忘录模式,关键看三个角色怎么配合:

1. Originator(发起人)

这是需要保存状态的对象。它负责创建备忘录并记录当前状态,也能利用备忘录恢复之前的状态。简单来说,它是状态的拥有者。

2. Memento(备忘录)

这是存储 Originator 状态的对象。它有两个接口:宽接口供 Originator 使用以存取数据,窄接口供其他对象使用仅用于保存。这样既保证了数据能存下来,又防止了外部随意修改内部细节。

3. Caretaker(管理者)

它只负责管理备忘录对象,比如存一堆快照。CareTaker 不操作备忘录内容,只能通过窄接口交互。职责单一,耦合度低。

设计原则体现

这个模式其实暗合了不少设计原则:

  • 单一职责:把状态保存从业务逻辑里剥离出来,Originator 专心干活。
  • 开闭原则:想扩展保存功能?加个新备忘录类就行,不用改 Originator。
  • 迪米特法则:Caretaker 不懂 Memento 内部细节,系统更松耦合。

C++ 实战代码

下面是一个完整的示例。注意,这里我用了智能指针来管理内存,避免手动 delete 带来的泄漏风险,这在 C++ 里是必须的。

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

// 备忘录类:存储状态
// 只有 Originator 可以通过友元访问私有成员
class Memento {
private:
    std::string state;
    friend class Originator;

    Memento(const std::string& s) : state(s) {}

public:
    // 窄接口:获取状态(通常由 Originator 调用)
    std::string GetState() const { return state; }
};

// 发起人类:产生和恢复状态
class Originator {
private:
    std::string state;

public:
    void SetState(const std::string& s) {
        std::cout << "设置状态:" << s << std::endl;
        state = s;
    }

    // 创建备忘录
    std::unique_ptr<Memento> CreateMemento() {
        return std::make_unique<Memento>(state);
    }

    // 恢复状态
    void RestoreFromMemento(const Memento* m) {
        state = m->GetState();
        std::cout << "恢复状态:" << state << std::endl;
    }
};

// 管理者类:保管备忘录
// 使用 unique_ptr 自动管理生命周期
class Caretaker {
private:
    std::vector<std::unique_ptr<Memento>> mementos;
    Originator* originator;

public:
    Caretaker(Originator* orig) : originator(orig) {}

    void Save() {
        mementos.push_back(originator->CreateMemento());
    }

    void Undo() {
        if (mementos.empty()) return;
        auto m = mementos.back();
        originator->RestoreFromMemento(m.get());
        mementos.pop_back();
    }
};

int main() {
    Originator originator;
    Caretaker caretaker(&originator);

    originator.SetState("状态 1");
    caretaker.Save();

    originator.SetState("状态 2");
    caretaker.Save();

    originator.SetState("状态 3");

    // 执行撤销,回到状态 2
    caretaker.Undo();
    // 再撤销,回到状态 1
    caretaker.Undo();

    return 0;
}

写这段代码时,有几个点值得注意:

  1. 内存安全:C++ 里指针满天飞,用 std::unique_ptr 能让资源管理更省心,尤其是 Caretaker 里的备忘录列表。
  2. 封装性:Memento 的构造函数是私有的,防止外部直接实例化,保证状态只能由 Originator 生成。
  3. 接口隔离:Caretaker 拿到的只是 const Memento*,没法篡改里面的 state。

典型应用场景

这模式不是万能的,但在这些地方很香:

  1. 撤销/重做功能:文本编辑器最经典的应用。
  2. 事务回滚:数据库操作失败时恢复现场。
  3. 游戏存档:保存进度,随时读档。
  4. 配置管理:保留历史配置版本。

高级特性与优化

实际项目中,还得考虑这些情况:

  • 增量备忘录:如果状态变化不大,别每次都存全量,只记差异能省内存。
  • 序列化支持:想把快照存到文件或数据库?加上序列化逻辑就行。
  • 线程安全:多线程环境下,记得加锁保护共享状态。

与其他模式的协作

备忘录很少单打独斗,常和命令模式一起出现。命令模式负责封装动作,备忘录负责记录动作前的状态,两者结合就能做出完美的撤销栈。

注意事项

最后提醒几个坑:

  1. 内存消耗:大对象频繁快照会吃内存,按需保存。
  2. 性能开销:深拷贝状态可能耗时,评估一下场景。
  3. 替代方案:有时候原型模式(克隆)比备忘录更简单,看需求选。

总结

备忘录模式通过状态封装实现了灵活的回滚机制,是面向对象设计的优秀实践。在 C++ 中实现时,重点要处理好内存管理和接口边界。掌握它,能让你的系统更加健壮、易维护。

目录

  1. C++备忘录模式:优雅实现对象状态保存与恢复
  2. 核心角色解析
  3. 1. Originator(发起人)
  4. 2. Memento(备忘录)
  5. 3. Caretaker(管理者)
  6. 设计原则体现
  7. C++ 实战代码
  8. 典型应用场景
  9. 高级特性与优化
  10. 与其他模式的协作
  11. 注意事项
  12. 总结

更多推荐文章

查看全部
  • AI 产品经理入门基础与核心知识体系
  • 2025 年秋招 LLM 及多模态模型面试精华
  • Claude Skills 技术详解与实战指南
  • 纯 Java 手写 TopoJSON 生成器:零依赖实现 GeoJSON 转换
  • C++26 反射驱动类型检查重塑代码质量
  • Whisper-large-v3 语音识别服务搭建与使用指南
  • AI 智能客服系统构建方案:选型指南与实战避坑
  • 大模型技术:检索增强生成 RAG 详解
  • 飞书机器人与 Claude Code 交互:从手机指令到 AI 处理的全自动流程
  • 爬虫与大模型结合实践:从基础提取到框架应用
  • C 语言数据结构与算法基础:文件操作、排序查找及链表简介
  • Python 面试高频题:从可变对象到垃圾回收机制
  • 大模型微调七步法:构建垂直领域专用模型
  • AI 产品经理面试核心考点与实战指南
  • 2025 年免费数字人工具评测:五大 AI 平台对比
  • 数据结构顺序表定义、操作与综合应用题解析
  • AI 驱动的产品落地全流程:从需求挖掘到上线管控实战
  • Rust 核心内存安全机制:所有权、借用与生命周期
  • RAG 提升大语言模型能力的三大关键技术
  • C/C++ 算法入门:一维动态规划基础实战

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online