当前位置: 首页 > news >正文

第二十二章:记忆封存,时光回溯——Memento的备忘录艺术

第二十二章:记忆封存,时光回溯——Memento的备忘录艺术

风云际会,备忘录史官登场

在Mediator展示完他那精妙的中介艺术后,Memento手持"记忆之书"的神秘史官走出。

"Mediator兄的协调解耦确实精妙,"Memento神秘地说道,“但在需要保存和恢复对象状态时,需要更加完善的状态管理机制。我的备忘录模式,可以在不破坏封装性的前提下,捕获一个对象的内部状态,并在之后将该对象恢复到之前的状态。存档、读档、撤销操作,皆赖于我。”

架构老人眼中闪过赞许之色:“善!Memento,就请你为大家展示这状态记忆的精妙所在。”

备忘录模式的核心要义

Memento面向众人,开始阐述他的武学真谛:

“在我的备忘录模式中,主要包含三个核心角色:”

Memento(备忘录):存储原始对象的内部状态。根据原始对象来决定保存哪些内部状态。”

Originator(原发器):创建一个备忘录,记录当前时刻的内部状态。也可以使用备忘录恢复内部状态。”

Caretaker(负责人):负责保存备忘录,但不能对备忘录的内容进行操作或检查。”

"其精妙之处在于,"Memento继续道,“我通过备忘录对象将原始对象的内部状态保存起来,并在需要的时候恢复,而不会破坏原始对象的封装性。这样,原始对象就不需要暴露其内部状态,同时又能实现撤销操作。”

C++实战:游戏存档系统

"且让我以一个游戏存档系统为例,展示备忘录模式的实战应用。"Memento说着,手中凝聚出一道道代码流光。

基础框架搭建

首先,Memento定义了备忘录、原发器和负责人的接口:

#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
#include <map>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <ctime>
#include <stack>
#include <random>// 前向声明
class GameState;// 备忘录接口
class GameMemento {
public:virtual ~GameMemento() = default;// 获取备忘录信息virtual std::string getName() const = 0;virtual std::string getTimestamp() const = 0;virtual std::string getDescription() const = 0;// 备忘录元数据virtual int getVersion() const = 0;virtual std::string getGameVersion() const = 0;// 备忘录操作virtual bool isValid() const = 0;virtual std::string getChecksum() const = 0;
};// 具体备忘录:游戏状态备忘录
class ConcreteGameMemento : public GameMemento {
private:std::string name_;std::string timestamp_;std::string gameVersion_;int version_;// 游戏状态数据std::string playerData_;std::string worldData_;std::string inventoryData_;std::string questData_;// 元数据std::string checksum_;bool isValid_;public:ConcreteGameMemento(const std::string& name, const std::string& gameVersion,const std::string& playerData, const std::string& worldData,const std::string& inventoryData, const std::string& questData): name_(name), gameVersion_(gameVersion), version_(1),playerData_(playerData), worldData_(worldData),inventoryData_(inventoryData), questData_(questData),isValid_(true) {// 生成时间戳auto now = std::chrono::system_clock::now();std::time_t time = std::chrono::system_clock::to_time_t(now);std::tm* localTime = std::localtime(&time);std::stringstream ss;ss << std::put_time(localTime, "%Y-%m-%d %H:%M:%S");timestamp_ = ss.str();// 生成简单的校验和checksum_ = generateChecksum();std::cout << "💾 创建游戏备忘录: " << name_ << " [版本:" << gameVersion_ << "]" << std::endl;}std::string getName() const override {return name_;}std::string getTimestamp() const override {return timestamp_;}std::string getDescription() const override {std::stringstream ss;ss << "游戏存档: " << name_ << " [时间:" << timestamp_ << " 游戏版本:" << gameVersion_ << " 数据版本:" << version_ << "]";return ss.str();}int getVersion() const override {return version_;}std::string getGameVersion() const override {return gameVersion_;}bool isValid() const override {return isValid_ && (generateChecksum() == checksum_);}std::string getChecksum() const override {return checksum_;}// 获取游戏状态数据std::string getPlayerData() const { return playerData_; }std::string getWorldData() const { return worldData_; }std::string getInventoryData() const { return inventoryData_; }std::string getQuestData() const { return questData_; }// 设置无效(模拟数据损坏)void setInvalid() {isValid_ = false;std::cout << "❌ 备忘录标记为无效: " << name_ << std::endl;}private:std::string generateChecksum() const {// 简化的校验和生成std::string data = playerData_ + worldData_ + inventoryData_ + questData_;size_t hash = std::hash<std::string>{}(data);return std::to_string(hash);}
};// 原发器:游戏状态
class GameState {
private:std::string gameVersion_;// 游戏状态数据std::string playerName_;int playerLevel_;int playerHealth_;int playerMana_;double playerExperience_;std::string currentLocation_;std::vector<std::string> visitedLocations_;std::map<std::string, int> inventory_;int gold_;std::map<std::string, std::string> activeQuests_;std::vector<std::string> completedQuests_;// 游戏统计int playTimeMinutes_;int enemiesDefeated_;int questsCompleted_;public:GameState(const std::string& gameVersion = "1.0.0"): gameVersion_(gameVersion), playerLevel_(1), playerHealth_(100), playerMana_(50), playerExperience_(0.0), gold_(0),playTimeMinutes_(0), enemiesDefeated_(0), questsCompleted_(0) {std::cout << "🎮 创建游戏状态 [版本:" << gameVersion_ << "]" << std::endl;initializeDefaultState();}// 创建备忘录std::shared_ptr<GameMemento> createMemento(const std::string& saveName) {std::cout << "💾 创建游戏存档: " << saveName << std::endl;// 序列化游戏状态数据std::string playerData = serializePlayerData();std::string worldData = serializeWorldData();std::string inventoryData = serializeInventoryData();std::string questData = serializeQuestData();return std::make_shared<ConcreteGameMemento>(saveName, gameVersion_, playerData, worldData, inventoryData, questData);}// 从备忘录恢复void restoreFromMemento(const GameMemento& memento) {if (!memento.isValid()) {std::cout << "❌ 无法恢复,备忘录无效: " << memento.getName() << std::endl;return;}const ConcreteGameMemento* concreteMemento = dynamic_cast<const ConcreteGameMemento*>(&memento);if (!concreteMemento) {std::cout << "❌ 备忘录类型不匹配" << std::endl;return;}std::cout << "🔄 从存档恢复: " << memento.getName() << std::endl;// 反序列化游戏状态数据deserializePlayerData(concreteMemento->getPlayerData());deserializeWorldData(concreteMemento->getWorldData());deserializeInventoryData(concreteMemento->getInventoryData());deserializeQuestData(concreteMemento->getQuestData());std::cout << "✅ 游戏状态恢复完成" << std::endl;}// 游戏操作void setPlayerInfo(const std::string& name, int level) {playerName_ = name;playerLevel_ = level;std::cout << "👤 设置玩家: " << playerName_ << " 等级:" << playerLevel_ << std::endl;}void addExperience(double exp) {playerExperience_ += exp;std::cout << "⭐ 获得经验: " << exp << " 总经验:" << playerExperience_ << std::endl;// 简化的升级逻辑if (playerExperience_ >= playerLevel_ * 100) {playerLevel_++;playerHealth_ += 20;playerMana_ += 10;std::cout << "🎉 升级! 新等级: " << playerLevel_ << std::endl;}}void changeLocation(const std::string& location) {currentLocation_ = location;if (std::find(visitedLocations_.begin(), visitedLocations_.end(), location) == visitedLocations_.end()) {visitedLocations_.push_back(location);}std::cout << "🗺️  移动到: " << currentLocation_ << std::endl;}void addItem(const std::string& item, int quantity = 1) {inventory_[item] += quantity;std::cout << "🎒 获得物品: " << item << " x" << quantity << std::endl;}void removeItem(const std::string& item, int quantity = 1) {if (inventory_.find(item) != inventory_.end()) {inventory_[item] -= quantity;if (inventory_[item] <= 0) {inventory_.erase(item);}std::cout << "🎒 消耗物品: " << item << " x" << quantity << std::endl;}}void addGold(int amount) {gold_ += amount;std::cout << "💰 获得金币: " << amount << " 总金币:" << gold_ << std::endl;}void startQuest(const std::string& questId, const std::string& questName) {activeQuests_[questId] = questName;std::cout << "📜 开始任务: " << questName << " [ID:" << questId << "]" << std::endl;}void completeQuest(const std::string& questId) {if (activeQuests_.find(questId) != activeQuests_.end()) {std::string questName = activeQuests_[questId];completedQuests_.push_back(questName);activeQuests_.erase(questId);questsCompleted_++;std::cout << "✅ 完成任务: " << questName << std::endl;// 任务奖励addExperience(50);addGold(100);}}void addPlayTime(int minutes) {playTimeMinutes_ += minutes;}void defeatEnemy() {enemiesDefeated_++;addExperience(10);addGold(5);std::cout << "⚔️  击败敌人! 总数:" << enemiesDefeated_ << std::endl;}// 显示游戏状态void displayStatus() const {std::cout << "\n🎮 游戏状态" << std::endl;std::cout << "==========" << std::endl;std::cout << "玩家: " << playerName_ << " 等级:" << playerLevel_ << std::endl;std::cout << "生命值: " << playerHealth_ << " 法力值:" << playerMana_ << std::endl;std::cout << "经验值: " << playerExperience_ << std::endl;std::cout << "当前位置: " << currentLocation_ << std::endl;std::cout << "金币: " << gold_ << std::endl;std::cout << "游戏时间: " << playTimeMinutes_ << "分钟" << std::endl;std::cout << "击败敌人: " << enemiesDefeated_ << "个" << std::endl;std::cout << "完成任务: " << questsCompleted_ << "个" << std::endl;}void displayInventory() const {std::cout << "\n🎒 背包" << std::endl;std::cout << "======" << std::endl;if (inventory_.empty()) {std::cout << "   (空)" << std::endl;} else {for (const auto& [item, quantity] : inventory_) {std::cout << "   • " << item << " x" << quantity << std::endl;}}}void displayQuests() const {std::cout << "\n📜 任务" << std::endl;std::cout << "======" << std::endl;std::cout << "进行中的任务:" << std::endl;if (activeQuests_.empty()) {std::cout << "   (无)" << std::endl;} else {for (const auto& [id, name] : activeQuests_) {std::cout << "   • " << name << " [ID:" << id << "]" << std::endl;}}std::cout << "已完成的任务:" << std::endl;if (completedQuests_.empty()) {std::cout << "   (无)" << std::endl;} else {for (const auto& quest : completedQuests_) {std::cout << "   • " << quest << std::endl;}}}private:void initializeDefaultState() {playerName_ = "冒险者";currentLocation_ = "起始村庄";visitedLocations_.push_back(currentLocation_);// 初始物品inventory_["生命药水"] = 3;inventory_["法力药水"] = 2;inventory_["面包"] = 5;// 初始任务startQuest("Q001", "新手教程");std::cout << "✅ 初始化默认游戏状态完成" << std::endl;}// 序列化方法std::string serializePlayerData() const {std::stringstream ss;ss << playerName_ << "|" << playerLevel_ << "|" << playerHealth_ << "|" << playerMana_ << "|" << playerExperience_ << "|" << playTimeMinutes_ << "|"<< enemiesDefeated_ << "|" << questsCompleted_;return ss.str();}std::string serializeWorldData() const {std::stringstream ss;ss << currentLocation_ << "|";for (size_t i = 0; i < visitedLocations_.size(); ++i) {ss << visitedLocations_[i];if (i < visitedLocations_.size() - 1) ss << ",";}return ss.str();}std::string serializeInventoryData() const {std::stringstream ss;ss << gold_ << "|";for (const auto& [item, quantity] : inventory_) {ss << item << ":" << quantity << ",";}return ss.str();}std::string serializeQuestData() const {std::stringstream ss;// 序列化进行中的任务for (const auto& [id, name] : activeQuests_) {ss << id << ":" << name << ";";}ss << "|";// 序列化已完成的任务for (const auto& quest : completedQuests_) {ss << quest << ",";}return ss.str();}// 反序列化方法void deserializePlayerData(const std::string& data) {std::stringstream ss(data);std::string token;std::vector<std::string> tokens;while (std::getline(ss, token, '|')) {tokens.push_back(token);}if (tokens.size() >= 8) {playerName_ = tokens[0];playerLevel_ = std::stoi(tokens[1]);playerHealth_ = std::stoi(tokens[2]);playerMana_ = std::stoi(tokens[3]);playerExperience_ = std::stod(tokens[4]);playTimeMinutes_ = std::stoi(tokens[5]);enemiesDefeated_ = std::stoi(tokens[6]);questsCompleted_ = std::stoi(tokens[7]);}}void deserializeWorldData(const std::string& data) {std::stringstream ss(data);std::getline(ss, currentLocation_, '|');std::string locationsStr;std::getline(ss, locationsStr);visitedLocations_.clear();std::stringstream locSs(locationsStr);std::string location;while (std::getline(locSs, location, ',')) {if (!location.empty()) {visitedLocations_.push_back(location);}}}void deserializeInventoryData(const std::string& data) {std::stringstream ss(data);std::string goldStr;std::getline(ss, goldStr, '|');gold_ = std::stoi(goldStr);std::string inventoryStr;std::getline(ss, inventoryStr);inventory_.clear();std::stringstream invSs(inventoryStr);std::string itemEntry;while (std::getline(invSs, itemEntry, ',')) {if (!itemEntry.empty()) {size_t colonPos = itemEntry.find(':');if (colonPos != std::string::npos) {std::string item = itemEntry.substr(0, colonPos);int quantity = std::stoi(itemEntry.substr(colonPos + 1));inventory_[item] = quantity;}}}}void deserializeQuestData(const std::string& data) {std::stringstream ss(data);std::string activeQuestsStr;std::getline(ss, activeQuestsStr, '|');std::string completedQuestsStr;std::getline(ss, completedQuestsStr);// 反序列化进行中的任务activeQuests_.clear();std::stringstream activeSs(activeQuestsStr);std::string questEntry;while (std::getline(activeSs, questEntry, ';')) {if (!questEntry.empty()) {size_t colonPos = questEntry.find(':');if (colonPos != std::string::npos) {std::string id = questEntry.substr(0, colonPos);std::string name = questEntry.substr(colonPos + 1);activeQuests_[id] = name;}}}// 反序列化已完成的任务completedQuests_.clear();std::stringstream completedSs(completedQuestsStr);std::string quest;while (std::getline(completedSs, quest, ',')) {if (!quest.empty()) {completedQuests_.push_back(quest);}}}
};

负责人实现

Memento展示了存档管理器的具体实现:

// 负责人:存档管理器
class SaveManager {
private:std::map<std::string, std::shared_ptr<GameMemento>> saves_;std::stack<std::shared_ptr<GameMemento>> undoStack_;std::stack<std::shared_ptr<GameMemento>> redoStack_;int maxSaves_;std::string currentGameVersion_;public:SaveManager(const std::string& gameVersion, int maxSaves = 10): currentGameVersion_(gameVersion), maxSaves_(maxSaves) {std::cout << "💾 创建存档管理器 [游戏版本:" << currentGameVersion_ << " 最大存档数:" << maxSaves_ << "]" << std::endl;}// 保存游戏bool saveGame(const std::string& saveName, GameState& gameState) {if (saves_.size() >= maxSaves_) {std::cout << "❌ 存档数量已达上限 (" << maxSaves_ << ")" << std::endl;return false;}if (saves_.find(saveName) != saves_.end()) {std::cout << "⚠️  存档已存在,将覆盖: " << saveName << std::endl;}auto memento = gameState.createMemento(saveName);saves_[saveName] = memento;// 添加到撤销栈undoStack_.push(memento);std::cout << "✅ 保存成功: " << saveName << std::endl;return true;}// 加载游戏bool loadGame(const std::string& saveName, GameState& gameState) {auto it = saves_.find(saveName);if (it == saves_.end()) {std::cout << "❌ 存档不存在: " << saveName << std::endl;return false;}auto memento = it->second;if (!memento->isValid()) {std::cout << "❌ 存档已损坏: " << saveName << std::endl;return false;}if (memento->getGameVersion() != currentGameVersion_) {std::cout << "⚠️  存档版本不匹配: " << memento->getGameVersion() << " (当前版本:" << currentGameVersion_ << ")" << std::endl;}gameState.restoreFromMemento(*memento);std::cout << "✅ 加载成功: " << saveName << std::endl;return true;}// 删除存档bool deleteSave(const std::string& saveName) {auto it = saves_.find(saveName);if (it == saves_.end()) {std::cout << "❌ 存档不存在: " << saveName << std::endl;return false;}saves_.erase(it);std::cout << "🗑️  删除存档: " << saveName << std::endl;return true;}// 自动保存bool autoSave(GameState& gameState) {std::string saveName = "自动存档_" + getCurrentTimestamp();return saveGame(saveName, gameState);}// 快速保存bool quickSave(GameState& gameState) {std::string saveName = "快速存档";return saveGame(saveName, gameState);}// 快速加载bool quickLoad(GameState& gameState) {return loadGame("快速存档", gameState);}// 撤销操作bool undo(GameState& gameState) {if (undoStack_.size() <= 1) { // 至少保留一个状态std::cout << "❌ 无法撤销,没有更多历史状态" << std::endl;return false;}auto currentState = undoStack_.top();undoStack_.pop();redoStack_.push(currentState);auto previousState = undoStack_.top();gameState.restoreFromMemento(*previousState);std::cout << "↩️  撤销到: " << previousState->getDescription() << std::endl;return true;}// 重做操作bool redo(GameState& gameState) {if (redoStack_.empty()) {std::cout << "❌ 无法重做,没有可重做的操作" << std::endl;return false;}auto state = redoStack_.top();redoStack_.pop();undoStack_.push(state);gameState.restoreFromMemento(*state);std::cout << "↪️  重做到: " << state->getDescription() << std::endl;return true;}// 列出所有存档void listSaves() const {std::cout << "\n📁 存档列表 (" << saves_.size() << "/" << maxSaves_ << ")" << std::endl;std::cout << "==========" << std::endl;if (saves_.empty()) {std::cout << "   (无存档)" << std::endl;return;}int index = 1;for (const auto& [name, memento] : saves_) {std::string status = memento->isValid() ? "✅" : "❌";std::cout << "   " << index << ". " << status << " " << memento->getDescription() << std::endl;index++;}}// 显示存档统计void showSaveStats() const {std::cout << "\n📊 存档统计" << std::endl;std::cout << "==========" << std::endl;std::cout << "总存档数: " << saves_.size() << std::endl;std::cout << "最大存档数: " << maxSaves_ << std::endl;int validSaves = 0;std::map<std::string, int> versionStats;for (const auto& [name, memento] : saves_) {if (memento->isValid()) validSaves++;versionStats[memento->getGameVersion()]++;}std::cout << "有效存档: " << validSaves << std::endl;std::cout << "无效存档: " << (saves_.size() - validSaves) << std::endl;std::cout << "版本分布:" << std::endl;for (const auto& [version, count] : versionStats) {std::cout << "  • " << version << ": " << count << " 个" << std::endl;}}// 验证所有存档void validateAllSaves() {std::cout << "\n🔍 验证所有存档..." << std::endl;int validCount = 0;for (const auto& [name, memento] : saves_) {if (memento->isValid()) {validCount++;std::cout << "   ✅ " << name << " - 有效" << std::endl;} else {std::cout << "   ❌ " << name << " - 无效" << std::endl;}}std::cout << "验证完成: " << validCount << "/" << saves_.size() << " 有效" << std::endl;}// 清理无效存档void cleanupInvalidSaves() {std::vector<std::string> toDelete;for (const auto& [name, memento] : saves_) {if (!memento->isValid()) {toDelete.push_back(name);}}for (const auto& name : toDelete) {deleteSave(name);}std::cout << "🧹 清理了 " << toDelete.size() << " 个无效存档" << std::endl;}private:std::string getCurrentTimestamp() {auto now = std::chrono::system_clock::now();std::time_t time = std::chrono::system_clock::to_time_t(now);std::tm* localTime = std::localtime(&time);std::stringstream ss;ss << std::put_time(localTime, "%Y%m%d_%H%M%S");return ss.str();}
};

UML 武功秘籍图

creates
stores/manages
«interface»
GameMemento
+getName() : string
+getTimestamp() : string
+getDescription() : string
+getVersion() : int
+getGameVersion() : string
+isValid() : bool
+getChecksum() : string
ConcreteGameMemento
-string name_
-string timestamp_
-string gameVersion_
-int version_
-string playerData_
-string worldData_
-string inventoryData_
-string questData_
-string checksum_
-bool isValid_
+getName() : string
+getTimestamp() : string
+getDescription() : string
+getVersion() : int
+getGameVersion() : string
+isValid() : bool
+getChecksum() : string
+getPlayerData() : string
+getWorldData() : string
+getInventoryData() : string
+getQuestData() : string
+setInvalid() : void
GameState
-string gameVersion_
-string playerName_
-int playerLevel_
-int playerHealth_
-int playerMana_
-double playerExperience_
-string currentLocation_
-vector<string> visitedLocations_
-map<string,int> inventory_
-int gold_
-map<string,string> activeQuests_
-vector<string> completedQuests_
-int playTimeMinutes_
-int enemiesDefeated_
-int questsCompleted_
+createMemento(string)
+restoreFromMemento(GameMemento) : void
+setPlayerInfo(string, int) : void
+addExperience(double) : void
+changeLocation(string) : void
+addItem(string, int) : void
+removeItem(string, int) : void
+addGold(int) : void
+startQuest(string, string) : void
+completeQuest(string) : void
+addPlayTime(int) : void
+defeatEnemy() : void
+displayStatus() : void
+displayInventory() : void
+displayQuests() : void
SaveManager
-map<string,GameMemento*> saves_
-stack<GameMemento*> undoStack_
-stack<GameMemento*> redoStack_
-int maxSaves_
-string currentGameVersion_
+saveGame(string, GameState&) : bool
+loadGame(string, GameState&) : bool
+deleteSave(string) : bool
+autoSave(GameState&) : bool
+quickSave(GameState&) : bool
+quickLoad(GameState&) : bool
+undo(GameState&) : bool
+redo(GameState&) : bool
+listSaves() : void
+showSaveStats() : void
+validateAllSaves() : void
+cleanupInvalidSaves() : void

实战演练:高级存档系统

Memento继续展示更复杂的备忘录模式应用:

// 高级备忘录:压缩备忘录
class CompressedGameMemento : public GameMemento {
private:std::string name_;std::string timestamp_;std::string gameVersion_;int version_;// 压缩数据std::vector<uint8_t> compressedData_;size_t originalSize_;std::string checksum_;bool isValid_;public:CompressedGameMemento(const std::string& name, const std::string& gameVersion,const std::string& playerData, const std::string& worldData,const std::string& inventoryData, const std::string& questData): name_(name), gameVersion_(gameVersion), version_(1), isValid_(true) {// 生成时间戳auto now = std::chrono::system_clock::now();std::time_t time = std::chrono::system_clock::to_time_t(now);std::tm* localTime = std::localtime(&time);std::stringstream ss;ss << std::put_time(localTime, "%Y-%m-%d %H:%M:%S");timestamp_ = ss.str();// 压缩数据std::string combinedData = playerData + "||" + worldData + "||" + inventoryData + "||" + questData;originalSize_ = combinedData.size();compressedData_ = compressData(combinedData);// 生成校验和checksum_ = generateChecksum(combinedData);std::cout << "🗜️  创建压缩备忘录: " << name_ << " [压缩率:" << std::fixed << std::setprecision(1)<< (100.0 - (compressedData_.size() * 100.0 / originalSize_)) << "%]" << std::endl;}std::string getName() const override { return name_; }std::string getTimestamp() const override { return timestamp_; }std::string getDescription() const override {std::stringstream ss;ss << "压缩存档: " << name_ << " [时间:" << timestamp_ << " 版本:" << gameVersion_ << " 压缩:" << compressedData_.size() << "/" << originalSize_ << "字节]";return ss.str();}int getVersion() const override { return version_; }std::string getGameVersion() const override { return gameVersion_; }bool isValid() const override {if (!isValid_) return false;// 解压缩并验证std::string decompressed = decompressData();return generateChecksum(decompressed) == checksum_;}std::string getChecksum() const override { return checksum_; }// 获取解压缩后的数据std::string getPlayerData() const {std::string data = decompressData();return extractDataPart(data, 0);}std::string getWorldData() const {std::string data = decompressData();return extractDataPart(data, 1);}std::string getInventoryData() const {std::string data = decompressData();return extractDataPart(data, 2);}std::string getQuestData() const {std::string data = decompressData();return extractDataPart(data, 3);}void setInvalid() {isValid_ = false;std::cout << "❌ 压缩备忘录标记为无效: " << name_ << std::endl;}// 获取压缩信息double getCompressionRatio() const {return originalSize_ > 0 ? (compressedData_.size() * 100.0 / originalSize_) : 0.0;}size_t getCompressedSize() const { return compressedData_.size(); }size_t getOriginalSize() const { return originalSize_; }private:std::vector<uint8_t> compressData(const std::string& data) {// 简化的"压缩" - 实际系统中会使用真正的压缩算法std::vector<uint8_t> compressed;for (char c : data) {compressed.push_back(static_cast<uint8_t>(c));}return compressed;}std::string decompressData() const {std::string decompressed;for (uint8_t byte : compressedData_) {decompressed += static_cast<char>(byte);}return decompressed;}std::string extractDataPart(const std::string& data, int partIndex) const {std::stringstream ss(data);std::string token;std::vector<std::string> parts;// 使用"||"作为分隔符size_t pos = 0;size_t lastPos = 0;std::string delimiter = "||";while ((pos = data.find(delimiter, lastPos)) != std::string::npos) {parts.push_back(data.substr(lastPos, pos - lastPos));lastPos = pos + delimiter.length();}parts.push_back(data.substr(lastPos));return partIndex < static_cast<int>(parts.size()) ? parts[partIndex] : "";}std::string generateChecksum(const std::string& data) const {size_t hash = std::hash<std::string>{}(data);return std::to_string(hash);}
};// 高级游戏状态:支持压缩存档
class AdvancedGameState : public GameState {
public:AdvancedGameState(const std::string& gameVersion = "1.0.0") : GameState(gameVersion) {std::cout << "🚀 创建高级游戏状态" << std::endl;}// 创建压缩备忘录std::shared_ptr<GameMemento> createCompressedMemento(const std::string& saveName) {std::cout << "🗜️  创建压缩存档: " << saveName << std::endl;// 序列化游戏状态数据std::string playerData = serializePlayerData();std::string worldData = serializeWorldData();std::string inventoryData = serializeInventoryData();std::string questData = serializeQuestData();return std::make_shared<CompressedGameMemento>(saveName, getGameVersion(), playerData, worldData, inventoryData, questData);}// 显示压缩信息void displayCompressionInfo(const GameMemento& memento) {const CompressedGameMemento* compressedMemento = dynamic_cast<const CompressedGameMemento*>(&memento);if (compressedMemento) {std::cout << "📦 压缩信息: " << compressedMemento->getCompressedSize() << "/" << compressedMemento->getOriginalSize() << " 字节 "<< "(压缩率: " << std::fixed << std::setprecision(1)<< compressedMemento->getCompressionRatio() << "%)" << std::endl;}}
};// 高级存档管理器:支持压缩和加密
class AdvancedSaveManager : public SaveManager {
private:bool useCompression_;bool useEncryption_;std::string encryptionKey_;public:AdvancedSaveManager(const std::string& gameVersion, int maxSaves = 10,bool compression = true, bool encryption = false): SaveManager(gameVersion, maxSaves), useCompression_(compression),useEncryption_(encryption) {if (encryption) {encryptionKey_ = generateEncryptionKey();}std::cout << "🔒 创建高级存档管理器" << std::endl;std::cout << "   压缩: " << (useCompression_ ? "启用" : "禁用") << std::endl;std::cout << "   加密: " << (useEncryption_ ? "启用" : "禁用") << std::endl;}// 高级保存方法bool saveGameAdvanced(const std::string& saveName, AdvancedGameState& gameState, bool compressed = true, bool encrypted = false) {if (saves_.size() >= getMaxSaves()) {std::cout << "❌ 存档数量已达上限" << std::endl;return false;}std::shared_ptr<GameMemento> memento;if (compressed) {memento = gameState.createCompressedMemento(saveName);} else {memento = gameState.createMemento(saveName);}if (encrypted && useEncryption_) {memento = encryptMemento(memento);}saves_[saveName] = memento;getUndoStack().push(memento);std::cout << "✅ 高级保存成功: " << saveName << std::endl;return true;}// 备份存档bool backupSave(const std::string& saveName, const std::string& backupName) {auto it = saves_.find(saveName);if (it == saves_.end()) {std::cout << "❌ 源存档不存在: " << saveName << std::endl;return false;}std::string backupNameFinal = backupName.empty() ? saveName + "_backup_" + getCurrentTimestamp() : backupName;saves_[backupNameFinal] = it->second; // 共享指针,实际是浅拷贝std::cout << "📦 备份存档: " << saveName << " → " << backupNameFinal << std::endl;return true;}// 导出存档bool exportSave(const std::string& saveName, const std::string& filePath) {auto it = saves_.find(saveName);if (it == saves_.end()) {std::cout << "❌ 存档不存在: " << saveName << std::endl;return false;}// 模拟导出到文件std::cout << "📤 导出存档: " << saveName << " → " << filePath << std::endl;std::cout << "   备忘录信息: " << it->second->getDescription() << std::endl;return true;}// 导入存档bool importSave(const std::string& filePath, const std::string& saveName) {// 模拟从文件导入std::cout << "📥 导入存档: " << filePath << " → " << saveName << std::endl;// 创建模拟的备忘录auto memento = std::make_shared<ConcreteGameMemento>(saveName, getCurrentGameVersion(), "导入的玩家数据", "导入的世界数据","导入的物品数据", "导入的任务数据");saves_[saveName] = memento;std::cout << "✅ 导入成功: " << saveName << std::endl;return true;}// 显示详细统计void showDetailedStats() const {std::cout << "\n📊 详细存档统计" << std::endl;std::cout << "==============" << std::endl;int normalSaves = 0;int compressedSaves = 0;int encryptedSaves = 0;size_t totalSize = 0;size_t totalCompressedSize = 0;for (const auto& [name, memento] : saves_) {if (dynamic_cast<const CompressedGameMemento*>(memento.get())) {compressedSaves++;auto compressedMemento = dynamic_cast<const CompressedGameMemento*>(memento.get());totalCompressedSize += compressedMemento->getCompressedSize();totalSize += compressedMemento->getOriginalSize();} else {normalSaves++;// 估算普通存档大小totalSize += 1024; // 假设每个普通存档1KB}if (useEncryption_) {encryptedSaves++; // 简化处理}}std::cout << "普通存档: " << normalSaves << " 个" << std::endl;std::cout << "压缩存档: " << compressedSaves << " 个" << std::endl;std::cout << "加密存档: " << encryptedSaves << " 个" << std::endl;std::cout << "总数据量: " << totalSize << " 字节" << std::endl;std::cout << "压缩后数据: " << totalCompressedSize << " 字节" << std::endl;if (totalSize > 0) {double compressionRatio = (1.0 - static_cast<double>(totalCompressedSize) / totalSize) * 100.0;std::cout << "总体压缩率: " << std::fixed << std::setprecision(1) << compressionRatio << "%" << std::endl;}}private:// 简化实现,获取受保护的成员std::stack<std::shared_ptr<GameMemento>>& getUndoStack() {return const_cast<std::stack<std::shared_ptr<GameMemento>>&>(static_cast<const SaveManager*>(this)->undoStack_);}int getMaxSaves() const { return maxSaves_; }std::string getCurrentGameVersion() const { return currentGameVersion_; }std::string generateEncryptionKey() {std::string key = "encryption_key_";key += getCurrentTimestamp();return key;}std::shared_ptr<GameMemento> encryptMemento(std::shared_ptr<GameMemento> memento) {std::cout << "🔐 加密备忘录: " << memento->getName() << std::endl;// 简化实现,实际系统中会进行真正的加密return memento;}std::string getCurrentTimestamp() {auto now = std::chrono::system_clock::now();std::time_t time = std::chrono::system_clock::to_time_t(now);std::tm* localTime = std::localtime(&time);std::stringstream ss;ss << std::put_time(localTime, "%Y%m%d_%H%M%S");return ss.str();}
};

完整测试代码

// 测试备忘录模式
void testMementoPattern() {std::cout << "=== 备忘录模式测试开始 ===" << std::endl;// 创建游戏状态和存档管理器std::cout << "\n--- 初始化游戏 ---" << std::endl;GameState gameState("1.0.0");SaveManager saveManager("1.0.0", 5);// 设置玩家信息gameState.setPlayerInfo("武林侠客", 1);gameState.addPlayTime(30);// 进行游戏操作std::cout << "\n--- 游戏进程 ---" << std::endl;gameState.defeatEnemy();gameState.addItem("青铜剑");gameState.addGold(50);gameState.changeLocation("青龙镇");// 保存游戏std::cout << "\n--- 保存游戏 ---" << std::endl;saveManager.saveGame("初始存档", gameState);// 继续游戏std::cout << "\n--- 继续游戏 ---" << std::endl;gameState.defeatEnemy();gameState.defeatEnemy();gameState.addExperience(45);gameState.addItem("生命药水", 2);gameState.startQuest("Q002", "剿灭山贼");// 快速保存saveManager.quickSave(gameState);// 显示游戏状态gameState.displayStatus();gameState.displayInventory();gameState.displayQuests();// 列出存档saveManager.listSaves();// 测试撤销std::cout << "\n--- 测试撤销 ---" << std::endl;saveManager.undo(gameState);gameState.displayStatus();// 测试重做std::cout << "\n--- 测试重做 ---" << std::endl;saveManager.redo(gameState);gameState.displayStatus();// 完成一些任务后再次保存std::cout << "\n--- 完成任务 ---" << std::endl;gameState.completeQuest("Q001");saveManager.saveGame("任务完成存档", gameState);// 显示存档统计saveManager.showSaveStats();std::cout << "\n=== 基础备忘录模式测试结束 ===" << std::endl;
}// 测试高级功能
void testAdvancedFeatures() {std::cout << "\n=== 高级功能测试开始 ===" << std::endl;// 创建高级游戏状态和存档管理器AdvancedGameState advancedGameState("2.0.0");AdvancedSaveManager advancedSaveManager("2.0.0", 8, true, true);// 设置玩家信息advancedGameState.setPlayerInfo("高级侠客", 5);advancedGameState.addPlayTime(120);// 进行游戏操作advancedGameState.defeatEnemy();advancedGameState.addItem("玄铁重剑");advancedGameState.addGold(200);advancedGameState.changeLocation("玄武城");advancedGameState.startQuest("Q003", "寻找失传秘籍");// 使用高级保存std::cout << "\n--- 高级保存 ---" << std::endl;advancedSaveManager.saveGameAdvanced("高级存档", advancedGameState, true, true);advancedSaveManager.quickSave(advancedGameState);// 显示游戏状态advancedGameState.displayStatus();// 备份存档std::cout << "\n--- 备份存档 ---" << std::endl;advancedSaveManager.backupSave("高级存档", "高级存档_备份");// 导出导入测试std::cout << "\n--- 导出导入测试 ---" << std::endl;advancedSaveManager.exportSave("高级存档", "./saves/advanced_save.dat");advancedSaveManager.importSave("./saves/imported_save.dat", "导入的存档");// 显示详细统计advancedSaveManager.showDetailedStats();advancedSaveManager.listSaves();std::cout << "\n=== 高级功能测试结束 ===" << std::endl;
}// 实战应用:完整的游戏存档系统
class CompleteGameSaveSystem {
private:std::unique_ptr<AdvancedSaveManager> saveManager_;std::unique_ptr<AdvancedGameState> currentGame_;std::string currentPlayer_;public:CompleteGameSaveSystem() {std::cout << "🎮 创建完整游戏存档系统" << std::endl;initializeSystem();}void initializeSystem() {saveManager_ = std::make_unique<AdvancedSaveManager>("2.1.0", 10, true, true);currentGame_ = std::make_unique<AdvancedGameState>("2.1.0");currentPlayer_ = "默认玩家";std::cout << "✅ 系统初始化完成" << std::endl;}void startNewGame(const std::string& playerName) {currentPlayer_ = playerName;currentGame_ = std::make_unique<AdvancedGameState>("2.1.0");currentGame_->setPlayerInfo(playerName, 1);currentGame_->addPlayTime(0);std::cout << "\n🎯 开始新游戏: " << playerName << std::endl;}void simulateGameplay() {std::cout << "\n🎮 模拟游戏进程..." << std::endl;std::cout << "==================" << std::endl;// 第一阶段std::cout << "\n--- 第一阶段: 新手村 ---" << std::endl;currentGame_->changeLocation("新手村");currentGame_->defeatEnemy();currentGame_->addItem("木剑");currentGame_->addGold(20);currentGame_->startQuest("QT001", "熟悉环境");currentGame_->addPlayTime(15);saveManager_->saveGame("新手村进度", *currentGame_);// 第二阶段std::cout << "\n--- 第二阶段: 野外冒险 ---" << std::endl;currentGame_->changeLocation("幽暗森林");currentGame_->defeatEnemy();currentGame_->defeatEnemy();currentGame_->addExperience(35);currentGame_->addItem("皮甲");currentGame_->addGold(45);currentGame_->completeQuest("QT001");currentGame_->startQuest("QT002", "清除狼群");currentGame_->addPlayTime(30);saveManager_->quickSave(*currentGame_);// 第三阶段std::cout << "\n--- 第三阶段: 城镇任务 ---" << std::endl;currentGame_->changeLocation("清风镇");currentGame_->defeatEnemy();currentGame_->addExperience(25);currentGame_->addItem("铁剑");currentGame_->addGold(80);currentGame_->completeQuest("QT002");currentGame_->startQuest("QT003", "护送商队");currentGame_->addPlayTime(25);saveManager_->saveGame("城镇任务完成", *currentGame_);std::cout << "\n✅ 游戏进程模拟完成" << std::endl;}void demonstrateSaveFeatures() {std::cout << "\n💾 演示存档功能..." << std::endl;std::cout << "==================" << std::endl;// 显示当前游戏状态std::cout << "\n--- 当前游戏状态 ---" << std::endl;currentGame_->displayStatus();currentGame_->displayInventory();currentGame_->displayQuests();// 显示存档列表std::cout << "\n--- 存档列表 ---" << std::endl;saveManager_->listSaves();// 测试撤销重做std::cout << "\n--- 撤销重做演示 ---" << std::endl;saveManager_->undo(*currentGame_);currentGame_->displayStatus();saveManager_->redo(*currentGame_);currentGame_->displayStatus();// 备份和导出std::cout << "\n--- 备份和导出 ---" << std::endl;saveManager_->backupSave("城镇任务完成", "重要进度备份");saveManager_->exportSave("城镇任务完成", "./backups/town_quest.dat");// 显示统计信息std::cout << "\n--- 系统统计 ---" << std::endl;saveManager_->showDetailedStats();// 验证存档std::cout << "\n--- 存档验证 ---" << std::endl;saveManager_->validateAllSaves();}void runCompleteDemo() {std::cout << "\n🚀 运行完整存档系统演示..." << std::endl;std::cout << "========================" << std::endl;startNewGame("武林盟主");simulateGameplay();demonstrateSaveFeatures();std::cout << "\n✅ 完整演示完成" << std::endl;}
};// 测试数据损坏和恢复
void testDataCorruptionAndRecovery() {std::cout << "\n=== 数据损坏和恢复测试 ===" << std::endl;GameState gameState("1.5.0");SaveManager saveManager("1.5.0", 5);// 正常游戏操作gameState.setPlayerInfo("测试玩家", 3);gameState.defeatEnemy();gameState.addItem("测试物品");// 保存正常存档saveManager.saveGame("正常存档", gameState);// 模拟数据损坏std::cout << "\n--- 模拟数据损坏 ---" << std::endl;auto it = const_cast<std::map<std::string, std::shared_ptr<GameMemento>>&>(saveManager.getSaves()).find("正常存档");if (it != saveManager.getSaves().end()) {auto concreteMemento = std::dynamic_pointer_cast<ConcreteGameMemento>(it->second);if (concreteMemento) {concreteMemento->setInvalid();}}// 尝试加载损坏的存档std::cout << "\n--- 尝试加载损坏存档 ---" << std::endl;GameState recoveryState("1.5.0");bool success = saveManager.loadGame("正常存档", recoveryState);if (!success) {std::cout << "❌ 加载损坏存档失败(符合预期)" << std::endl;}// 清理损坏存档std::cout << "\n--- 清理损坏存档 ---" << std::endl;saveManager.cleanupInvalidSaves();saveManager.listSaves();std::cout << "\n=== 数据损坏和恢复测试结束 ===" << std::endl;
}int main() {std::cout << "🌈 设计模式武林大会 - 备忘录模式演示 🌈" << std::endl;std::cout << "=====================================" << std::endl;// 测试基础备忘录模式testMementoPattern();// 测试高级功能testAdvancedFeatures();// 测试数据损坏和恢复testDataCorruptionAndRecovery();// 运行完整存档系统演示std::cout << "\n=== 完整游戏存档系统演示 ===" << std::endl;CompleteGameSaveSystem gameSystem;gameSystem.runCompleteDemo();std::cout << "\n🎉 备忘录模式演示全部完成!" << std::endl;return 0;
}

备忘录模式的武学心得

适用场景

  • 状态保存:当需要保存一个对象在某一时刻的状态,以便以后恢复时
  • 撤销操作:当需要实现撤销操作功能时
  • 快照功能:当需要实现对象状态的快照功能时
  • 事务回滚:当需要实现事务回滚机制时

优点

  • 封装性好:在不破坏对象封装性的前提下保存和恢复状态
  • 状态管理:简化了原始对象的状态管理,将状态保存和恢复的责任分离
  • 易于实现:可以方便地实现撤销和重做功能
  • 状态比较:可以比较不同时刻保存的状态

缺点

  • 资源消耗:如果状态数据很大,会占用较多内存
  • 性能影响:频繁保存状态可能会影响性能
  • 实现复杂度:在需要保存大量状态或状态变化频繁时,实现可能变得复杂

武林高手的点评

Command 赞叹道:“Memento 兄的状态保存确实精妙!能够如此优雅地实现撤销和重做功能,这在需要状态管理的系统中确实无人能及。”

State 也点头称赞:“Memento 兄专注于状态的保存和恢复,而我更关注状态的变化和行为。我们都有助于管理对象的状态。”

Memento 谦虚回应:“诸位过奖了。每个模式都有其适用场景。在需要保存和恢复状态时,我的备忘录模式确实能发挥重要作用。但在需要封装操作时,Command 兄的方法更加合适。”

下章预告

在Memento展示完他那精妙的状态记忆艺术后,Interpreter 正在解析一段古老的符文的语言学家走出。

“Memento 兄的状态记忆确实精妙,但在需要解释特定语言或文法时,需要更加专业的解释机制。” Interpreter 专注地说道,“下一章,我将展示如何通过解释器模式定义语言的文法表示,并解释语言中的句子!”

架构老人满意地点头:“善!语言解释确实是编译原理和规则引擎的核心。下一章,就请 Interpreter 展示他的解释艺术!”


欲知 Interpreter 如何通过解释器模式实现语言的解释,且听下回分解!

http://www.dtcms.com/a/453574.html

相关文章:

  • Spring Framework源码解析——ApplicationContextAware
  • 30个做设计的网站wordpress远程图片下载
  • 建网站权威机构西安专业网站建设服务
  • Express+Vue表格数据分页联调:模拟数据与真实接口的无缝切换
  • Qt 多线程与并发编程详解
  • 第五个实验——动态nat地址转换操作
  • 排查 TCP 连接中 TIME_WAIT 状态异常
  • 《C++ 实际应用系列》第二部分:内存管理与性能优化实战
  • 登建设厅锁子的是哪个网站祥云平台网站管理系统
  • 浙江省建设厅网站在哪里手机网站制作招聘
  • nat server 概念及题目
  • 试看30秒做受小视频网站深圳外贸网站制作
  • 网站营销推广怎么做网络营销推广网站建设关于公司怎么写
  • 【AI】专访 Braintrust CEO Ankur Goyal:为什么 AI 评测是产品 prototype 走向生产的唯一桥梁?
  • 大模型文生图和语音转换的调用以及向量和向量数据库RedisStack.
  • 做代练去什么网站安全合肥网站seo整站优化
  • 网站案例展示怎么做桂电做网站的毕设容易过嘛
  • QT-常用控件(一)
  • 网站开发选asp还是hph网站域名解析步骤
  • AI行业应用深度解析:从理论到实践的跨越
  • DeepMind 和罗光记团队 推出“帧链”概念:视频模型或将实现全面视觉理解
  • 外贸圈阿里巴巴微信seo什么意思
  • 【专业词汇】元认知
  • 有什么网站开发软件网页棋牌开发
  • Flutter与Dart结合AI开发实战
  • Easyx使用(数据可视化)
  • 基于单片机的大货车防偷油系统设计
  • JavaScript:神奇的ES6之旅
  • 延吉网站开发公司特别好的企业网站程序
  • Avalonia:现代跨平台UI开发的卓越之选