C++ 设计模式-备忘录模式

news/2025/2/22 6:22:06

游戏存档实现,包括撤销/重做、持久化存储、版本控制和内存管理

#include <iostream>
#include <memory>
#include <deque>
#include <stack>
#include <chrono>
#include <fstream>
#include <sstream>
#include <ctime>

// ================ 1. 增强版备忘录类 ================
class GameMemento {
private:
    const int level;
    const int health;
    const std::string weapon;
    const std::chrono::system_clock::time_point timestamp;

    friend class GameCharacter;

public:
    GameMemento(int lv, int hp, std::string wp, std::chrono::system_clock::time_point ts)
        : level(lv), health(hp), weapon(std::move(wp)), timestamp(ts) {}

    // 序列化为字符串
    std::string serialize() const {
        std::time_t ts = std::chrono::system_clock::to_time_t(timestamp);
        std::stringstream ss;
        ss << level << "," << health << "," << weapon << "," << ts;
        return ss.str();
    }

    // 从字符串反序列化
    static std::unique_ptr<GameMemento> deserialize(const std::string& data) {
        std::stringstream ss(data);
        int lv, hp;
        std::string wp;
        time_t ts;

        char comma;
        ss >> lv >> comma >> hp >> comma;
        std::getline(ss, wp, ',');
        ss >> ts;

        return std::make_unique<GameMemento>(
            lv, hp, wp, std::chrono::system_clock::from_time_t(ts)
        );
    }

    void print() const {
        auto ts = std::chrono::system_clock::to_time_t(timestamp);
        char buffer[26];
        strftime(buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y", std::localtime(&ts));
        std::cout << "Lv." << level << " HP:" << health
          << " Weapon:" << weapon << " (" << buffer << ")\n";
    }
};

// ================ 2. 游戏角色类 ================
class GameCharacter {
private:
    int level = 1;
    int health = 100;
    std::string weapon = "Fist";

public:
    void levelUp() { level++; health += 20; }
    void takeDamage(int dmg) { health -= dmg; }
    void equipWeapon(std::string wp) { weapon = std::move(wp); }

    std::unique_ptr<GameMemento> save() const {
        return std::make_unique<GameMemento>(
            level, health, weapon,
            std::chrono::system_clock::now()
        );
    }

    void load(const GameMemento& memento) {
        level = memento.level;
        health = memento.health;
        weapon = memento.weapon;
    }

    void status() const {
        std::cout << "Current State: Lv." << level
                  << " HP:" << health
                  << " Weapon:" << weapon << "\n";
    }
};

// ================ 3. 增强版存档管理器 ================
class SaveManager {
private:
    std::deque<std::unique_ptr<GameMemento>> undoStack;  // 使用deque方便限制数量
    std::stack<std::unique_ptr<GameMemento>> redoStack;  // 重做栈
    const size_t MAX_SAVES = 5;  // 最大存档数量

    void trimHistory() {
        while (undoStack.size() > MAX_SAVES) {
            undoStack.pop_front();  // 移除最旧的存档
        }
    }

public:
    // 保存新状态
    void saveState(const GameCharacter& character) {
        undoStack.push_back(character.save());
        redoStack = std::stack<std::unique_ptr<GameMemento>>(); // 清空重做栈
        trimHistory();
    }

    // 撤销
    bool undo(GameCharacter& character) {
        if (undoStack.size() < 2) return false;

        redoStack.push(std::move(undoStack.back()));
        undoStack.pop_back();

        character.load(*undoStack.back());
        return true;
    }

    // 重做
    bool redo(GameCharacter& character) {
        if (redoStack.empty()) return false;

        character.load(*redoStack.top());
        undoStack.push_back(std::move(redoStack.top()));
        redoStack.pop();
        return true;
    }

    // 保存到文件
    bool saveToFile(const std::string& filename) const {
        std::ofstream file(filename);
        if (!file) return false;

        for (const auto& memento : undoStack) {
            file << memento->serialize() << "\n";
        }
        return true;
    }

    // 从文件加载
    bool loadFromFile(const std::string& filename, GameCharacter& character) {
        std::ifstream file(filename);
        if (!file) return false;

        undoStack.clear();
        redoStack = std::stack<std::unique_ptr<GameMemento>>();

        std::string line;
        while (std::getline(file, line)) {
            auto memento = GameMemento::deserialize(line);
            if (memento) {
                undoStack.push_back(std::move(memento));
            }
        }

        if (!undoStack.empty()) {
            character.load(*undoStack.back());
        }
        return true;
    }

    // 显示版本历史
    void showHistory() const {
        std::cout << "\n=== Version History (" << undoStack.size() << "/"
            << MAX_SAVES << ") ===\n";
        int i = 1;
        for (const auto& memento : undoStack) {
            std::cout << "Version " << i++ << ": ";
            memento->print();
        }
    }
};

// ================ 使用示例 ================
int main() {
    GameCharacter hero;
    SaveManager saveManager;

    // 初始状态
    hero.status();
    saveManager.saveState(hero);

    // 查看历史版本
    saveManager.showHistory();

    // 进行一系列操作
    hero.levelUp();
    hero.equipWeapon("Sword");
    saveManager.saveState(hero);

    hero.takeDamage(30);
    saveManager.saveState(hero);

    hero.levelUp();
    hero.equipWeapon("Axe");
    saveManager.saveState(hero);

    // 查看历史版本
    saveManager.showHistory();

    // 持久化存储
    saveManager.saveToFile("game_save.txt");

    // 连续撤销两次
    std::cout << "=== Undo x2 ===\n";
    saveManager.undo(hero);
    saveManager.undo(hero);
    hero.status();

    // 重做一次
    std::cout << "=== Redo x1 ===\n";
    saveManager.redo(hero);
    hero.status();

    // 从文件加载
    GameCharacter loadedHero;
    SaveManager loadManager;
    loadManager.loadFromFile("game_save.txt", loadedHero);
    std::cout << "=== Loaded Character ===\n";

    loadedHero.status();
    loadManager.showHistory();

    hero.takeDamage(-30);
    saveManager.saveState(hero);
    hero.status();
    // 查看历史版本
    saveManager.showHistory();


    return 0;
}

功能实现说明:

  1. 撤销/重做系统

    • 使用双栈结构(undoStack + redoStack)
    • undo() 保留最近两个状态以实现状态对比
    • 每次保存时清空重做栈
  2. 持久化存储

    • 使用CSV格式存储:level,health,weapon,timestamp
    • 支持从文件恢复完整历史记录
  3. 版本控制

    • 每个存档包含精确到秒的时间戳
    • showHistory() 显示带时间的版本信息
  4. 内存优化

    • 限制最大存档数量(MAX_SAVES = 5)
    • 自动移除最早的存档
  5. 附加功能

    • 版本历史浏览
    • 完整的异常安全设计
    • 使用现代C++特性(chrono时间库、智能指针等)

执行结果示例:

Current State: Lv.1 HP:100 Weapon:Fist

=== Version History (1/5) ===
Version 1: Lv.1 HP:100 Weapon:Fist (Fri Feb 21 12:10:21 2025)

=== Version History (4/5) ===
Version 1: Lv.1 HP:100 Weapon:Fist (Fri Feb 21 12:10:21 2025)
Version 2: Lv.2 HP:120 Weapon:Sword (Fri Feb 21 12:10:21 2025)
Version 3: Lv.2 HP:90 Weapon:Sword (Fri Feb 21 12:10:21 2025)
Version 4: Lv.3 HP:110 Weapon:Axe (Fri Feb 21 12:10:21 2025)
=== Undo x2 ===
Current State: Lv.2 HP:120 Weapon:Sword
=== Redo x1 ===
Current State: Lv.2 HP:90 Weapon:Sword
=== Loaded Character ===
Current State: Lv.3 HP:110 Weapon:Axe

=== Version History (4/5) ===
Version 1: Lv.1 HP:100 Weapon:Fist (Fri Feb 21 12:10:21 2025)
Version 2: Lv.2 HP:120 Weapon:Sword (Fri Feb 21 12:10:21 2025)
Version 3: Lv.2 HP:90 Weapon:Sword (Fri Feb 21 12:10:21 2025)
Version 4: Lv.3 HP:110 Weapon:Axe (Fri Feb 21 12:10:21 2025)
Current State: Lv.2 HP:120 Weapon:Sword

=== Version History (4/5) ===
Version 1: Lv.1 HP:100 Weapon:Fist (Fri Feb 21 12:10:21 2025)
Version 2: Lv.2 HP:120 Weapon:Sword (Fri Feb 21 12:10:21 2025)
Version 3: Lv.2 HP:90 Weapon:Sword (Fri Feb 21 12:10:21 2025)
Version 4: Lv.2 HP:120 Weapon:Sword (Fri Feb 21 12:10:21 2025)

http://www.niftyadmin.cn/n/5861776.html

相关文章

WPF 中显示图形的方式深度解析

一、引言 Windows Presentation Foundation(WPF)凭借其强大的图形渲染能力,为开发者打造美观、交互性强的桌面应用程序提供了有力支持。在 WPF 里,有多种显示图形的方式,每种方式都有独特的用途和特点。本文将详细介绍 DrawingImage、Shape、Image、GeometryDrawing、Dra…

汽车智能制造企业数字化转型SAP解决方案总结

一、项目实施概述 项目阶段划分&#xff1a; 蓝图设计阶段主数据管理方案各模块蓝图设计方案下一阶段工作计划 关键里程碑&#xff1a; 2022年6月6日&#xff1a;项目启动会2022年12月1日&#xff1a;系统上线 二、总体目标 通过SAP实施&#xff0c;构建研产供销协同、业财一…

随笔记:SpringBoot引入第三方jar包并包扫描问题

背景说明&#xff1a; 有两个SpringBoot工程&#xff08;代号A&#xff1a;标准产品&#xff0c;代号B&#xff1a;产品定制&#xff09; 代号B工程是一个空壳子工程&#xff0c;包结构如下图&#xff1a;分为接口包和实现包两个 在代号A工程中配置好 ComponentScan &#xf…

HarmonyOS 开发套件 介绍 ——上篇

HarmonyOS 开发套件 介绍 ——上篇 在当今科技飞速发展的时代&#xff0c;操作系统作为智能设备的核心&#xff0c;其重要性不言而喻。而HarmonyOS&#xff0c;作为华为推出的全新操作系统&#xff0c;正以其独特的魅力和强大的功能&#xff0c;吸引着越来越多的开发者和用户的…

计算机网络:应用层 —— 域名系统 DNS

文章目录 什么是域名系统 DNS&#xff1f;域名系统DNS的作用域名结构顶级域名二级域名因特网的域名空间 域名服务器域名解析的过程递归查询迭代查询 DNS本地高速缓存总结 什么是域名系统 DNS&#xff1f; 域名系统&#xff08;DNS&#xff0c;Domain Name System&#xff09;是…

Jenkins 视图(View)

Jenkins 视图(View) 一、视图是什么 Jenkins 视图(View) 如下图中 All、Apps 都是 Jenkisn 中的 View 左侧如果有 New View 或者 点击 All 这一行最右侧的 号&#xff0c;都可以创建视图 二、视图(View)的作用 点击最左侧的 All 可以看到所有的任务 随着项目不断发展&am…

rpc和http的区别,为啥golang使用grpc 不使用http?

RPC 和 HTTP 的区别 概念层面 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;&#xff1a;是一种允许程序调用另一个地址空间&#xff08;通常是共享网络上的另一台机器&#xff09;中的过程或函数的技术&#xff0c;就像调用本地函数一样自然。…

【Pandas】pandas Series sample

Pandas2.2 Series Computations descriptive stats 方法描述Series.align(other[, join, axis, level, …])用于将两个 Series 对齐&#xff0c;使其具有相同的索引Series.case_when(caselist)用于根据条件列表对 Series 中的元素进行条件判断并返回相应的值Series.drop([lab…