C++ 设计模式-备忘录模式
游戏存档实现,包括撤销/重做、持久化存储、版本控制和内存管理
#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;
}
功能实现说明:
-
撤销/重做系统:
- 使用双栈结构(undoStack + redoStack)
undo()保留最近两个状态以实现状态对比- 每次保存时清空重做栈
-
持久化存储:
- 使用CSV格式存储:
level,health,weapon,timestamp - 支持从文件恢复完整历史记录
- 使用CSV格式存储:
-
版本控制:
- 每个存档包含精确到秒的时间戳
showHistory()显示带时间的版本信息
-
内存优化:
- 限制最大存档数量(MAX_SAVES = 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)
相关文章:
C++ 设计模式-备忘录模式
游戏存档实现,包括撤销/重做、持久化存储、版本控制和内存管理 #include <iostream> #include <memory> #include <deque> #include <stack> #include <chrono> #include <fstream> #include <sstream> #include <ct…...
TOGAF之架构标准规范-信息系统架构 | 应用架构
TOGAF是工业级的企业架构标准规范,信息系统架构阶段是由数据架构阶段以及应用架构阶段构成,本文主要描述信息系统架构阶段中的应用架构阶段。 如上所示,信息系统架构(Information Systems Architectures)在TOGAF标准规…...
第一届网谷杯
统计四场的所有题目(共计12题,四场比赛一共上了21题【包括换题】) 随便记记,以免老题复用(已经复用了) Web 文件包含 1 伪协议 http://120.202.175.143:8011/?cphp://filter/convert.base64-encode/reso…...
Linux(ubuntu) GPU CUDA 构建Docker镜像
一、创建Dockerfile FROM ubuntu:20.04#非交互式,以快速运行自动化任务或脚本,无需图形界面 ENV DEBIAN_FRONTENDnoninteractive# 安装基础工具 RUN apt-get update && apt-get install -y \curl \wget \git \build-essential \software-proper…...
mysql -DQL语句和DCL语句
DQL 数据查询语言(Data Query Language,DQL)是数据库操作语言的重要组成部分,主要用于从数据库中检索数据,核心关键字为SELECT。以下从语法结构、常见操作及示例等方面详细介绍: 语法结构 DQL 的标准语法…...
掌握 ElasticSearch 组合查询:Bool Query 详解与实践
掌握 ElasticSearch 组合查询:Bool Query 详解与实践 一、引言 (Introduction)二、Bool 查询基础2.1 什么是 Bool 查询?2.2 Bool 查询的四种子句2.3 语法结构 三、Bool 查询的四种子句详解与示例3.1 must 子句3.2 filter 子句3.3 should 子句3.4 must_no…...
C++ 类和对象(友元、内部类、匿名对像)
目录 一、前言 二、正文 1.友元 1.1友元函数的使用 1.1.1外部友元函数可访问类的私有成员,友员函数仅仅是一种声明,他不是类的成员函数。 1.1.2一个函数可以是多个类的友元函数 2.友元类的使用 2.1什么是友元类 2.2 友元类的关系是单向的&#x…...
PostgreSQL 常用函数
PostgreSQL 常用函数 在数据库管理系统中,函数是执行特定任务的基本构建块。PostgreSQL 是一个功能强大的开源关系数据库管理系统,提供了丰富的内置函数,这些函数极大地增强了数据库操作的能力。以下是一些在 PostgreSQL 中常用的函数&#…...
掌握 ElasticSearch 四种match查询的原理与应用
文章目录 一、引言 (Introduction)二、准备工作:创建索引和添加示例数据三、match 查询四、match_all 查询五、multi_match 查询六、match_phrase 查询七、总结 (Conclusion) 一、引言 (Introduction) 在信息爆炸的时代,快速准确地找到所需信息至关重要…...
解决:Conda虚拟环境中未设置CUDA_HOME的问题
背景:我是Ubuntu22.04系统,最近在复现FoundationPose算法,按照README构建部署环境时,有一步一直卡住,看了下是未找到CUDA_HOME这个环境变量。 网上搜了下这个错误,需要设置CUDA_HOME的环境变量路径&#x…...
easyexcel和poi同时存在版本问题,使用easyexcel导出excel设置日期格式
这两天在使用easyexcel导出excel的时候日期格式全都是字符串导致导出的excel列无法筛选 后来调整了一下终于弄好了,看一下最终效果 这里涉及到easyexcel和poi版本冲突的问题,一直没搞定,最后狠下心来把所有的都升级到了最新版,然…...
HarmonyOS 开发套件 介绍——下篇
HarmonyOS 开发套件 介绍——下篇 在HarmonyOS的生态中,开发套件作为支撑整个系统发展的基石,为开发者提供了丰富而强大的工具和服务。本文将深入继续介绍HarmonyOS SDK、ArkCompiler、DevEco Testing、AppGallery等核心组件,帮助开发者全面掌…...
关于order by的sql注入实验
实验描述 本实验基于sqli-lab的第46关进行测试 本关的sql 语句为$sql "SELECT * FROM users ORDER BY $id" 利用sort进行sql注入,我们可以利用报错注入,延时注入来爆出数据 1.报错注入 1.手工测试 爆出数据库 ?sort(extractvalue(1, c…...
Transformers快速入门-学习笔记
一、自然语言处理 NLP 是借助计算机技术研究人类语言的科学自然语言处理发展史 一、不懂语法怎么理解语言 依靠语言学家人工总结文法规则 Chomsky Formal Languages 难点:上下文有关文法 规则增多,存在矛盾 二、只要看得足够多,就能处理语言…...
luci界面开发中的MVC架构——LuCI介绍(二)
想要给openwrt开发应用,虽然直接可执行程序也可以运行,但是没有UI会很不方便,想要开发UI就要用openwrt的那一套,自然就是LuCI,LuCI又用了一套MVC框架,今天就讲讲这是个什么东西。 OpenWrt LuCI 界面开发中…...
第1章大型互联网公司的基础架构——1.10 其他NoSQL数据库
这里我们简单介绍一下其他常见的NoSQL数据库及其适用的场景,其中部分数据库会在后续服务设计章节中正式使用时再做详细介绍。 1.10.1 文档数据库 文档数据库的典型代表是MongoDB和CouchDB。**文档数据库普遍采用JSON格式来存储数据,而不是采用僵硬的行…...
DeepSeek+Kimi生成高质量PPT
DeepSeek与Kimi生成PPT全流程解析 一、工具分工原理 DeepSeek核心作用:生成结构化PPT大纲(擅长逻辑构建与内容优化)Kimi核心作用:将文本转换为视觉化PPT(提供模板库与排版引擎) 二、操作步骤详解 1. 通…...
web网络安全:跨站脚本攻击(XSS)
跨站脚本攻击(XSS)概述 跨站脚本攻击(XSS,Cross-Site Scripting) 是一种常见的 Web 安全漏洞,攻击者通过向受信任的网站注入恶意脚本(通常是 JavaScript),诱使其他用户在…...
【Python爬虫(44)】分布式爬虫:筑牢安全防线,守护数据之旅
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取ÿ…...
微信小程序:多菜单栏设计效果
一、实现效果 二、代码 wxml 编辑前端界面,步骤 菜单逻辑: 逐步取出数组中的项,首先取出顶部菜单项,然后选中后取出选中的底部数据(左侧菜单+右侧内容),然后点击左侧菜单取出选中的左侧菜单对应的右侧内容 ①这里我的数据是全部封装到一个数组对象的,首先我的循环…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
