首页 智能家居

C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二)

分类:智能家居
字数: (2290)
阅读: (0003)
内容摘要:C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二),

在上一篇文章中,我们初步了解了备忘录模式的概念和基本实现。但实际应用中,仅仅保存对象的完整状态可能效率低下,而且某些敏感信息并不适合直接暴露。本文将继续深入探讨备忘录模式,重点解决状态存储优化和信息安全问题,并通过 C++ 代码示例进行详细讲解。

问题场景重现:大型对象的状态保存

假设我们正在开发一个游戏,玩家的角色拥有大量的属性(生命值、魔法值、装备、背包物品等)。每次玩家进行重要操作(如进入新地图、升级)时,都需要保存角色的状态以便回退。如果每次都完整复制整个角色对象,会消耗大量的内存和 CPU 资源。这就像我们在使用 Nginx 反向代理时,如果每次请求都记录完整的请求头和 body,在高并发场景下会对服务器造成巨大的压力。我们可以考虑只记录关键的变化部分,类似 Nginx 的 access log 只记录关键信息。

C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二)

底层原理深度剖析:增量式备忘录

增量式备忘录的核心思想是:只保存对象状态的差异,而不是完整状态。这需要我们在对象内部维护一个状态变化的历史记录,并在创建备忘录时,只保存最近的变化。在恢复状态时,按照相反的顺序应用这些变化,即可恢复到之前的状态。这种方式可以极大地减少内存消耗,尤其是在对象状态变化不频繁的情况下。

C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二)

具体代码/配置解决方案:C++ 增量式备忘录实现

下面是一个简单的 C++ 示例,演示如何使用增量式备忘录模式。

C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

class Originator {
public:
    Originator(int health, int mana, std::string item) : health_(health), mana_(mana), item_(item) {}

    void setHealth(int health) {
        history_.push_back([this, health]() { // 使用 lambda 表达式记录变化
            int oldHealth = health_; // 记录旧值
            health_ = health; // 设置新值
            return [this, oldHealth]() { // 返回一个 undo 操作的 lambda 表达式
                health_ = oldHealth; // 恢复旧值
            };
        });
        health_ = health;
    }

    void setMana(int mana) {
        history_.push_back([this, mana]() {
            int oldMana = mana_; // 记录旧值
            mana_ = mana; // 设置新值
            return [this, oldMana]() {
                mana_ = oldMana; // 恢复旧值
            };
        });
        mana_ = mana;
    }

    void setItem(std::string item) {
        history_.push_back([this, item]() {
            std::string oldItem = item_; // 记录旧值
            item_ = item; // 设置新值
            return [this, oldItem]() {
                item_ = oldItem; // 恢复旧值
            };
        });
        item_ = item;
    }

    int getHealth() const { return health_; }
    int getMana() const { return mana_; }
    std::string getItem() const { return item_; }

    void undo() {
        if (!history_.empty()) {
            auto undoAction = history_.back()(); // 执行 undo 操作
            undoAction(); // 恢复状态
            history_.pop_back(); // 移除该操作
        }
    }

private:
    int health_;
    int mana_;
    std::string item_;
    std::vector<std::function<std::function<void()>()>> history_; // 存储状态变化的历史记录
};

int main() {
    Originator player(100, 50, "Sword");
    std::cout << "Health: " << player.getHealth() << ", Mana: " << player.getMana() << ", Item: " << player.getItem() << std::endl;

    player.setHealth(80);
    player.setMana(60);
    player.setItem("Shield");
    std::cout << "Health: " << player.getHealth() << ", Mana: " << player.getMana() << ", Item: " << player.getItem() << std::endl;

    player.undo(); // 撤销上一次操作
    std::cout << "Health: " << player.getHealth() << ", Mana: " << player.getMana() << ", Item: " << player.getItem() << std::endl;

    player.undo(); // 再次撤销
    std::cout << "Health: " << player.getHealth() << ", Mana: " << player.getMana() << ", Item: " << player.getItem() << std::endl;

    return 0;
}

在这个例子中,Originator 类维护了一个 history_ 向量,用于存储状态变化的历史记录。每次调用 setHealthsetManasetItem 方法时,都会创建一个 lambda 表达式来记录变化,并将该 lambda 表达式添加到 history_ 中。undo 方法用于撤销上一次操作,它从 history_ 中取出最后一个 lambda 表达式,执行它,然后将其从 history_ 中移除。

C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二)

实战避坑经验总结

  • 状态粒度控制:需要仔细考虑应该保存哪些状态。如果粒度太细,会导致备忘录数量过多;如果粒度太粗,则可能无法完全恢复到之前的状态。
  • 线程安全问题:如果多个线程同时访问 Originator 对象,需要考虑线程安全问题,可以使用互斥锁来保护状态。
  • 内存管理:如果状态对象较大,需要注意内存管理,避免内存泄漏。可以使用智能指针来管理状态对象的生命周期。
  • 序列化与持久化:如果需要将备忘录持久化到磁盘,需要考虑状态对象的序列化问题。可以使用 Boost.Serialization 或其他序列化库。
  • 状态加密:对于敏感信息,可以使用加密算法对状态进行加密,确保信息安全,例如使用 AES 加密算法。

总之,备忘录模式是一种非常有用的设计模式,可以帮助我们实现状态回滚和历史记录功能。在实际应用中,需要根据具体情况选择合适的实现方式,并注意一些常见的坑点。 希望通过本文,您能对 设计模式 - 备忘录模式 有更深入的理解。

C++ 设计模式进阶:备忘录模式深度剖析与实战演练(二)

转载请注明出处: 脱发程序员

本文的链接地址: http://m.acea2.store/blog/070272.SHTML

本文最后 发布于2026-04-08 22:29:42,已经过了19天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 冬天里的一把火 4 天前
    这个例子可以再完善一下,加入更多的状态变化和 undo 操作,感觉更实用。
  • 非酋本酋 4 天前
    这个例子可以再完善一下,加入更多的状态变化和 undo 操作,感觉更实用。
  • 雨后的彩虹 3 天前
    这个例子可以再完善一下,加入更多的状态变化和 undo 操作,感觉更实用。
  • e人代表 4 天前
    增量式备忘录这个思路不错,可以有效减少内存占用,学习了!
  • 武汉热干面 4 天前
    C++ lambda 表达式那块有点绕,得多看几遍才能理解。