设计模式(C++)详解——备忘录模式(2)

<摘要>

备忘录模式是一种行为设计模式,它允许在不破坏对象封装性的前提下捕获和存储对象的内部状态,并在需要时将对象恢复到之前的状态。本文从模式的历史起源、核心概念入手,深入分析其设计哲学和实现考量,通过文本编辑器、游戏存档、绘图程序等多个实际案例展示具体应用,结合详细的C++代码实现和Mermaid图表说明,全面解析备忘录模式在软件开发中的价值和实现技巧。


<解析>

备忘录模式深度解析:时光倒流的艺术

1. 历史渊源与演进脉络

1.1 模式的诞生背景

备忘录模式的起源可以追溯到软件工程中一个永恒的需求:"撤销"功能。在早期的交互式软件中,用户期望能够回退操作,就像在现实生活中我们有时需要"反悔"一样。

时间线演进

时期 发展里程碑 代表性系统
1970s 早期文本编辑器的简单撤销 EMACS, Vi
1980s 图形界面软件的撤销/重做 MacPaint, Windows Paint
1994年 GoF正式定义备忘录模式 《设计模式》出版
2000s 模式在游戏和Web应用中普及 Photoshop, Word, 网页浏览器
现今 分布式系统的事务回滚 微服务架构, 数据库系统

1.2 现状与发展趋势

当前应用现状

  • 🎯 普遍性:几乎所有交互式软件都实现了某种形式的撤销功能
  • 🎯 复杂性:从简单的单步撤销发展到多级撤销树
  • 🎯 性能优化:增量保存、压缩存储等技术的应用

未来发展趋势

  • 🚀 AI增强:智能撤销建议、模式识别
  • 🚀 跨设备同步:云备份的撤销历史
  • 🚀 实时协作:多人协同编辑的冲突解决

2. 核心概念深度剖析

2.1 三大核心角色详解

Originator(发起人)

职责 :需要保存状态的对象
特征

  • 拥有重要的内部状态
  • 能够创建备忘录来保存当前状态
  • 能够使用备忘录恢复之前的状态
cpp 复制代码
/**
 * @brief 发起人抽象定义
 * 
 * 定义了创建和恢复备忘录的标准接口,是模式的核心参与者
 */
class Originator {
protected:
    // 需要保存的内部状态
    StateType internalState_;
    
public:
    /**
     * @brief 创建状态备忘录
     * 
     * 捕获当前对象的内部状态,并封装在备忘录对象中
     * 
     * @return Memento* 包含当前状态的备忘录对象
     */
    virtual std::unique_ptr<Memento> createMemento() const = 0;
    
    /**
     * @brief 从备忘录恢复状态
     * 
     * 使用备忘录中保存的状态来恢复对象的内部状态
     * 
     * @param memento 包含要恢复状态的备忘录
     */
    virtual void restoreFromMemento(const Memento* memento) = 0;
    
    /**
     * @brief 业务操作
     * 
     * 改变对象状态的操作,通常在执行后会创建备忘录
     */
    virtual void performOperation() = 0;
};
Memento(备忘录)

职责 :状态存储的封装容器
特征

  • 存储发起人的内部状态
  • 防止发起人之外的对象访问其内容
  • 提供有限的接口给发起人
cpp 复制代码
/**
 * @brief 备忘录基类
 * 
 * 定义备忘录的基本接口,具体的状态存储由子类实现
 */
class Memento {
public:
    virtual ~Memento() = default;
    
    /**
     * @brief 获取时间戳
     * 
     * 用于记录状态保存的时间,支持按时间排序
     * 
     * @return std::chrono::system_clock::time_point 保存时间
     */
    virtual std::chrono::system_clock::time_point getTimestamp() const = 0;
    
    /**
     * @brief 获取描述信息
     * 
     * 提供人类可读的描述,便于用户识别不同的状态点
     * 
     * @return std::string 描述信息
     */
    virtual std::string getDescription() const = 0;
};
Caretaker(管理者)

职责 :备忘录的生命周期管理
特征

  • 保存和管理备忘录对象
  • 不操作或检查备忘录内容
  • 提供历史记录管理功能
cpp 复制代码
/**
 * @brief 管理者基类
 * 
 * 负责备忘录的存储、检索和管理,但不了解备忘录的具体内容
 */
class Caretaker {
protected:
    std::vector<std::unique_ptr<Memento>> history_;
    size_t maxHistorySize_;
    
public:
    /**
     * @brief 保存备忘录
     * 
     * 将备忘录添加到历史记录中,可能涉及历史记录清理
     * 
     * @param memento 要保存的备忘录
     */
    virtual void saveMemento(std::unique_ptr<Memento> memento) = 0;
    
    /**
     * @brief 获取最近的备忘录
     * 
     * 从历史记录中检索最新的备忘录用于恢复
     * 
     * @return std::unique_ptr<Memento> 最近的备忘录
     */
    virtual std::unique_ptr<Memento> getLastMemento() = 0;
    
    /**
     * @brief 获取指定索引的备忘录
     * 
     * 支持按索引访问历史记录中的任意备忘录
     * 
     * @param index 备忘录索引
     * @return std::unique_ptr<Memento> 指定索引的备忘录
     */
    virtual std::unique_ptr<Memento> getMemento(size_t index) = 0;
};

2.2 完整的UML架构图

classDiagram class Originator { <> #internalState: StateType +createMemento() Memento* +restoreFromMemento(memento: Memento*) void +performOperation() void +getState() StateType +setState(state: StateType) void } class Memento { <> #timestamp: TimePoint #description: string +getTimestamp() TimePoint +getDescription() string } class ConcreteMemento { -savedState: StateType +ConcreteMemento(state: StateType, desc: string) +getState() StateType +getTimestamp() TimePoint +getDescription() string } class Caretaker { <> #history: vector~Memento*~ #maxSize: size_t +saveMemento(memento: Memento*) void +getLastMemento() Memento* +getMemento(index: size_t) Memento* +getHistorySize() size_t +clearHistory() void } class HistoryManager { -currentIndex: size_t +saveMemento(memento: Memento*) void +undo() Memento* +redo() Memento* +canUndo() bool +canRedo() bool +getHistoryList() vector~string~ } class Client { +main() } Originator --> Memento : creates Originator --> ConcreteMemento : uses Caretaker --> Memento : stores HistoryManager --> Caretaker Client --> Originator Client --> HistoryManager note for Originator "创建备忘录时保存状态\n恢复时从备忘录读取状态" note for Memento "封装状态,保护内部数据\n只有Originator可以访问细节" note for Caretaker "管理备忘录生命周期\n不操作备忘录内容"

3. 设计哲学与实现考量

3.1 核心设计原则

封装性保护

备忘录模式的核心价值在于在保存状态的同时保护封装性。这是一个微妙但重要的平衡:

cpp 复制代码
/**
 * @brief 文本编辑器备忘录 - 封装性实现示例
 * 
 * 通过友元关系和私有构造函数确保只有Originator可以访问备忘录内部
 */
class TextEditorMemento : public Memento {
private:
    // 私有数据,保护封装性
    std::string content_;
    TextFormat format_;
    CursorPosition cursorPos_;
    std::chrono::system_clock::time_point timestamp_;
    std::string description_;
    
    // 友元声明,只有TextEditor可以创建和访问备忘录
    friend class TextEditor;
    
    /**
     * @brief 私有构造函数
     * 
     * 确保只有TextEditor可以创建备忘录实例
     * 
     * @param content 文本内容
     * @param format 文本格式
     * @param cursor 光标位置
     * @param desc 描述信息
     */
    TextEditorMemento(const std::string& content, 
                     const TextFormat& format,
                     const CursorPosition& cursor,
                     const std::string& desc)
        : content_(content), format_(format), cursorPos_(cursor), 
          description_(desc) {
        timestamp_ = std::chrono::system_clock::now();
    }
    
public:
    // 公共接口只提供基本信息,不暴露内部状态细节
    std::chrono::system_clock::time_point getTimestamp() const override {
        return timestamp_;
    }
    
    std::string getDescription() const override {
        return description_;
    }
    
private:
    // 只有TextEditor可以访问的私有方法
    std::string getContent() const { return content_; }
    TextFormat getFormat() const { return format_; }
    CursorPosition getCursorPosition() const { return cursorPos_; }
};
职责分离

模式成功的关键在于清晰的职责划分:

角色 职责 不应当负责
Originator 状态创建和恢复 状态存储管理
Memento 状态安全存储 状态解释和操作
Caretaker 历史记录管理 状态内容访问

3.2 实现权衡与决策

存储策略选择

完整存储 vs 增量存储

cpp 复制代码
/**
 * @brief 完整状态备忘录
 * 
 * 保存对象的完整状态,实现简单但可能内存效率低
 */
class FullStateMemento : public Memento {
private:
    CompleteObjectState fullState_;
    // 存储整个对象状态
};

/**
 * @brief 增量状态备忘录
 * 
 * 只保存发生变化的部分,内存效率高但实现复杂
 */
class DeltaMemento : public Memento {
private:
    StateDifference delta_;
    std::shared_ptr<Memento> baseState_;
    // 只存储状态差异
};

权衡比较表

方面 完整存储 增量存储
实现复杂度 低 ✅ 高 ❌
内存使用 高 ❌ 低 ✅
恢复速度 快 ✅ 慢 ❌
适用场景 小对象状态 大对象状态
生命周期管理

内存管理策略

cpp 复制代码
/**
 * @brief 智能备忘录管理器
 * 
 * 使用智能指针自动管理备忘录生命周期,避免内存泄漏
 */
class SmartCaretaker : public Caretaker {
private:
    std::vector<std::shared_ptr<Memento>> history_;
    size_t currentIndex_;
    size_t maxSize_;
    
public:
    void saveMemento(std::shared_ptr<Memento> memento) override {
        // 清理当前索引之后的历史(重做分支)
        if (currentIndex_ < history_.size() - 1) {
            history_.resize(currentIndex_ + 1);
        }
        
        history_.push_back(memento);
        currentIndex_ = history_.size() - 1;
        
        // 限制历史记录大小
        if (history_.size() > maxSize_) {
            history_.erase(history_.begin());
            currentIndex_--;
        }
    }
    
    std::shared_ptr<Memento> undo() {
        if (currentIndex_ > 0) {
            currentIndex_--;
            return history_[currentIndex_];
        }
        return nullptr;
    }
    
    std::shared_ptr<Memento> redo() {
        if (currentIndex_ < history_.size() - 1) {
            currentIndex_++;
            return history_[currentIndex_];
        }
        return nullptr;
    }
};

3.3 性能优化策略

懒保存机制
cpp 复制代码
/**
 * @brief 智能起源器 - 支持懒保存
 * 
 * 只有在状态实际发生变化时才创建备忘录
 */
class SmartOriginator {
private:
    StateType currentState_;
    StateType lastSavedState_;
    bool isDirty_;
    
public:
    std::shared_ptr<Memento> createMementoIfNeeded() {
        if (isDirty_ && currentState_ != lastSavedState_) {
            auto memento = createMemento();
            lastSavedState_ = currentState_;
            isDirty_ = false;
            return memento;
        }
        return nullptr;
    }
    
    void markDirty() {
        isDirty_ = true;
    }
};

4. 综合实例分析

4.1 案例一:高级文本编辑器

需求分析

  • 支持多级撤销/重做
  • 保存文本内容、格式和光标位置
  • 支持保存点标记
  • 内存使用优化

完整实现

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <chrono>
#include <stack>

// 文本格式结构
struct TextFormat {
    std::string fontFamily;
    int fontSize;
    bool isBold;
    bool isItalic;
    std::string color;
    
    bool operator==(const TextFormat& other) const {
        return fontFamily == other.fontFamily &&
               fontSize == other.fontSize &&
               isBold == other.isBold &&
               isItalic == other.isItalic &&
               color == other.color;
    }
};

// 光标位置结构
struct CursorPosition {
    size_t line;
    size_t column;
    size_t selectionStart;
    size_t selectionEnd;
    
    bool operator==(const CursorPosition& other) const {
        return line == other.line &&
               column == other.column &&
               selectionStart == other.selectionStart &&
               selectionEnd == other.selectionEnd;
    }
};

// 文本编辑器状态
struct EditorState {
    std::string content;
    TextFormat format;
    CursorPosition cursor;
    std::string documentName;
    
    bool operator==(const EditorState& other) const {
        return content == other.content &&
               format == other.format &&
               cursor == other.cursor &&
               documentName == other.documentName;
    }
    
    bool operator!=(const EditorState& other) const {
        return !(*this == other);
    }
};

/**
 * @brief 文本编辑器备忘录
 * 
 * 保存文本编辑器的完整状态,包括内容、格式和光标位置
 */
class TextEditorMemento : public Memento {
private:
    EditorState savedState_;
    std::chrono::system_clock::time_point timestamp_;
    std::string description_;
    
    friend class AdvancedTextEditor;
    
    TextEditorMemento(const EditorState& state, const std::string& desc)
        : savedState_(state), description_(desc) {
        timestamp_ = std::chrono::system_clock::now();
    }
    
public:
    std::chrono::system_clock::time_point getTimestamp() const override {
        return timestamp_;
    }
    
    std::string getDescription() const override {
        return description_;
    }
    
private:
    // 只有AdvancedTextEditor可以访问
    EditorState getState() const {
        return savedState_;
    }
};

/**
 * @brief 高级文本编辑器 - 起源器实现
 * 
 * 支持丰富的文本编辑功能,可以创建和恢复备忘录
 */
class AdvancedTextEditor {
private:
    EditorState currentState_;
    std::string lastOperation_;
    
public:
    AdvancedTextEditor(const std::string& docName = "Untitled") {
        currentState_.documentName = docName;
        currentState_.content = "";
        currentState_.format = {"Arial", 12, false, false, "#000000"};
        currentState_.cursor = {0, 0, 0, 0};
    }
    
    /**
     * @brief 插入文本
     * 
     * 在当前位置插入文本,更新光标位置
     * 
     * @param text 要插入的文本
     */
    void insertText(const std::string& text) {
        // 实际实现会处理文本插入和光标更新
        currentState_.content += text;
        updateCursorAfterInsert(text.length());
        lastOperation_ = "插入文本: " + (text.length() > 10 ? 
                         text.substr(0, 10) + "..." : text);
    }
    
    /**
     * @brief 删除文本
     * 
     * 删除选定文本或光标前的内容
     */
    void deleteText() {
        if (hasSelection()) {
            // 删除选定内容
            size_t start = currentState_.cursor.selectionStart;
            size_t end = currentState_.cursor.selectionEnd;
            currentState_.content.erase(start, end - start);
            currentState_.cursor.column = start;
            clearSelection();
        } else if (currentState_.cursor.column > 0) {
            // 删除光标前一个字符
            currentState_.content.erase(currentState_.cursor.column - 1, 1);
            currentState_.cursor.column--;
        }
        lastOperation_ = "删除文本";
    }
    
    /**
     * @brief 设置文本格式
     * 
     * 应用指定的文本格式到选定内容或默认格式
     * 
     * @param format 新的文本格式
     */
    void setFormat(const TextFormat& format) {
        currentState_.format = format;
        lastOperation_ = "更改格式";
    }
    
    /**
     * @brief 创建备忘录
     * 
     * 捕获当前编辑器的完整状态
     * 
     * @return std::shared_ptr<TextEditorMemento> 状态备忘录
     */
    std::shared_ptr<TextEditorMemento> createMemento() const {
        std::string desc = lastOperation_ + " @" + 
                          std::to_string(currentState_.content.length()) + "字符";
        return std::make_shared<TextEditorMemento>(currentState_, desc);
    }
    
    /**
     * @brief 从备忘录恢复
     * 
     * 将编辑器状态恢复到备忘录保存时的状态
     * 
     * @param memento 要恢复的备忘录
     */
    void restoreFromMemento(std::shared_ptr<TextEditorMemento> memento) {
        currentState_ = memento->getState();
        lastOperation_ = "恢复状态";
    }
    
    /**
     * @brief 显示当前状态
     * 
     * 输出编辑器的当前内容摘要
     */
    void displayStatus() const {
        std::cout << "文档: " << currentState_.documentName << std::endl;
        std::cout << "内容: " 
                  << (currentState_.content.length() > 50 ? 
                      currentState_.content.substr(0, 50) + "..." : 
                      currentState_.content) 
                  << std::endl;
        std::cout << "长度: " << currentState_.content.length() << " 字符" << std::endl;
        std::cout << "光标: 行 " << currentState_.cursor.line 
                  << ", 列 " << currentState_.cursor.column << std::endl;
        if (hasSelection()) {
            std::cout << "选定: " << currentState_.cursor.selectionStart 
                      << " - " << currentState_.cursor.selectionEnd << std::endl;
        }
        std::cout << "---" << std::endl;
    }
    
private:
    bool hasSelection() const {
        return currentState_.cursor.selectionStart != currentState_.cursor.selectionEnd;
    }
    
    void clearSelection() {
        currentState_.cursor.selectionStart = currentState_.cursor.selectionEnd;
    }
    
    void updateCursorAfterInsert(size_t length) {
        currentState_.cursor.column += length;
        clearSelection();
    }
};

/**
 * @brief 高级历史管理器
 * 
 * 支持撤销/重做操作,限制历史记录大小
 */
class AdvancedHistoryManager {
private:
    std::vector<std::shared_ptr<TextEditorMemento>> undoStack_;
    std::vector<std::shared_ptr<TextEditorMemento>> redoStack_;
    size_t maxHistorySize_;
    size_t currentSavePoint_;
    
public:
    AdvancedHistoryManager(size_t maxSize = 100) 
        : maxHistorySize_(maxSize), currentSavePoint_(0) {}
    
    /**
     * @brief 保存状态
     * 
     * 将状态保存到撤销栈,清空重做栈
     * 
     * @param memento 要保存的备忘录
     */
    void saveState(std::shared_ptr<TextEditorMemento> memento) {
        undoStack_.push_back(memento);
        redoStack_.clear(); // 新的操作清空重做历史
        
        // 限制历史记录大小
        if (undoStack_.size() > maxHistorySize_) {
            undoStack_.erase(undoStack_.begin());
            if (currentSavePoint_ > 0) currentSavePoint_--;
        }
    }
    
    /**
     * @brief 撤销操作
     * 
     * 从撤销栈弹出状态,压入重做栈
     * 
     * @return std::shared_ptr<TextEditorMemento> 要恢复的状态
     */
    std::shared_ptr<TextEditorMemento> undo() {
        if (undoStack_.size() <= 1) return nullptr; // 需要至少2个状态才能撤销
        
        auto currentState = undoStack_.back();
        undoStack_.pop_back();
        redoStack_.push_back(currentState);
        
        return undoStack_.back(); // 返回前一个状态
    }
    
    /**
     * @brief 重做操作
     * 
     * 从重做栈弹出状态,压入撤销栈
     * 
     * @return std::shared_ptr<TextEditorMemento> 要恢复的状态
     */
    std::shared_ptr<TextEditorMemento> redo() {
        if (redoStack_.empty()) return nullptr;
        
        auto state = redoStack_.back();
        redoStack_.pop_back();
        undoStack_.push_back(state);
        
        return state;
    }
    
    /**
     * @brief 设置保存点
     * 
     * 标记当前状态为保存点,用于文档修改状态检测
     */
    void setSavePoint() {
        currentSavePoint_ = undoStack_.size();
    }
    
    /**
     * @brief 检查是否有未保存的修改
     * 
     * @return bool 是否有未保存的修改
     */
    bool hasUnsavedChanges() const {
        return undoStack_.size() != currentSavePoint_;
    }
    
    /**
     * @brief 是否可以撤销
     * 
     * @return bool 是否可以执行撤销
     */
    bool canUndo() const {
        return undoStack_.size() > 1;
    }
    
    /**
     * @brief 是否可以重做
     * 
     * @return bool 是否可以执行重做
     */
    bool canRedo() const {
        return !redoStack_.empty();
    }
    
    /**
     * @brief 获取历史记录信息
     * 
     * @return std::vector<std::string> 历史记录描述列表
     */
    std::vector<std::string> getHistoryInfo() const {
        std::vector<std::string> info;
        for (const auto& memento : undoStack_) {
            info.push_back(memento->getDescription());
        }
        return info;
    }
};

// 演示代码
int main() {
    std::cout << "🖊️ 高级文本编辑器演示" << std::endl;
    std::cout << "====================" << std::endl;
    
    // 创建编辑器和历史管理器
    AdvancedTextEditor editor("测试文档");
    AdvancedHistoryManager history(10); // 最多保存10个历史状态
    
    // 初始状态
    std::cout << "初始状态:" << std::endl;
    editor.displayStatus();
    history.saveState(editor.createMemento());
    
    // 一系列编辑操作
    std::cout << "执行编辑操作..." << std::endl;
    
    editor.insertText("你好,这是一个备忘录模式的演示。");
    history.saveState(editor.createMemento());
    editor.displayStatus();
    
    editor.insertText(" 我们正在测试撤销和重做功能。");
    history.saveState(editor.createMemento());
    editor.displayStatus();
    
    editor.insertText(" 这是第三段文本。");
    history.saveState(editor.createMemento());
    editor.displayStatus();
    
    // 执行撤销
    std::cout << "执行撤销操作..." << std::endl;
    if (history.canUndo()) {
        auto memento = history.undo();
        editor.restoreFromMemento(memento);
        editor.displayStatus();
    }
    
    // 再次撤销
    std::cout << "再次撤销..." << std::endl;
    if (history.canUndo()) {
        auto memento = history.undo();
        editor.restoreFromMemento(memento);
        editor.displayStatus();
    }
    
    // 执行重做
    std::cout << "执行重做..." << std::endl;
    if (history.canRedo()) {
        auto memento = history.redo();
        editor.restoreFromMemento(memento);
        editor.displayStatus();
    }
    
    // 显示历史信息
    std::cout << "历史记录:" << std::endl;
    auto historyInfo = history.getHistoryInfo();
    for (size_t i = 0; i < historyInfo.size(); ++i) {
        std::cout << i << ": " << historyInfo[i] << std::endl;
    }
    
    return 0;
}

时序图分析
User AdvancedTextEditor AdvancedHistoryManager TextEditorMemento 初始状态 insertText("第一段") 更新内容 createMemento() memento1 saveState(memento1) 继续编辑 insertText("第二段") 更新内容 createMemento() memento2 saveState(memento2) 撤销操作 undo() pop from undoStack push to redoStack memento1 restoreFromMemento(memento1) 重做操作 redo() pop from redoStack push to undoStack memento2 restoreFromMemento(memento2) User AdvancedTextEditor AdvancedHistoryManager TextEditorMemento

4.2 案例二:游戏存档系统

需求分析

  • 支持多个存档槽位
  • 保存玩家状态、游戏进度、物品栏
  • 快速保存/加载功能
  • 存档元数据管理

完整实现

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <chrono>

// 游戏角色状态
struct PlayerState {
    std::string name;
    int level;
    int experience;
    int health;
    int maxHealth;
    int mana;
    int maxMana;
    std::string currentLocation;
    std::vector<std::string> inventory;
    std::map<std::string, int> skills;
    
    void display() const {
        std::cout << "角色: " << name << " (Lv." << level << ")" << std::endl;
        std::cout << "生命: " << health << "/" << maxHealth;
        std::cout << " 魔法: " << mana << "/" << maxMana << std::endl;
        std::cout << "经验: " << experience << std::endl;
        std::cout << "位置: " << currentLocation << std::endl;
        std::cout << "物品栏: ";
        for (const auto& item : inventory) {
            std::cout << item << " ";
        }
        std::cout << std::endl;
    }
};

// 游戏世界状态
struct WorldState {
    std::map<std::string, bool> completedQuests;
    std::map<std::string, bool> discoveredLocations;
    std::chrono::system_clock::time_point gameTime;
    int totalPlayTime; // 秒
    
    void display() const {
        auto timeT = std::chrono::system_clock::to_time_t(gameTime);
        std::cout << "游戏时间: " << std::ctime(&timeT);
        std::cout << "总游戏时间: " << totalPlayTime / 3600 << "小时" 
                  << (totalPlayTime % 3600) / 60 << "分钟" << std::endl;
        std::cout << "完成任务: " << completedQuests.size() << "个" << std::endl;
    }
};

/**
 * @brief 游戏存档备忘录
 * 
 * 保存完整的游戏状态,包括玩家和世界状态
 */
class GameSaveMemento : public Memento {
private:
    PlayerState playerState_;
    WorldState worldState_;
    std::string saveName_;
    std::chrono::system_clock::time_point saveTime_;
    std::string description_;
    
    friend class GameSession;
    
    GameSaveMemento(const PlayerState& player, const WorldState& world,
                   const std::string& name, const std::string& desc)
        : playerState_(player), worldState_(world), saveName_(name), 
          description_(desc) {
        saveTime_ = std::chrono::system_clock::now();
    }
    
public:
    std::chrono::system_clock::time_point getTimestamp() const override {
        return saveTime_;
    }
    
    std::string getDescription() const override {
        return description_;
    }
    
    std::string getSaveName() const {
        return saveName_;
    }
    
private:
    PlayerState getPlayerState() const { return playerState_; }
    WorldState getWorldState() const { return worldState_; }
};

/**
 * @brief 游戏会话 - 起源器实现
 * 
 * 管理游戏状态,支持存档和读档
 */
class GameSession {
private:
    PlayerState currentPlayer_;
    WorldState currentWorld_;
    std::chrono::system_clock::time_point sessionStart_;
    
public:
    GameSession(const std::string& playerName) {
        currentPlayer_.name = playerName;
        currentPlayer_.level = 1;
        currentPlayer_.experience = 0;
        currentPlayer_.health = 100;
        currentPlayer_.maxHealth = 100;
        currentPlayer_.mana = 50;
        currentPlayer_.maxMana = 50;
        currentPlayer_.currentLocation = "起始村庄";
        currentPlayer_.inventory = {"新手剑", "治疗药水"};
        currentPlayer_.skills = {{"攻击", 1}, {"防御", 1}};
        
        currentWorld_.gameTime = std::chrono::system_clock::now();
        currentWorld_.totalPlayTime = 0;
        currentWorld_.completedQuests = {{"新手教程", true}};
        currentWorld_.discoveredLocations = {{"起始村庄", true}};
        
        sessionStart_ = std::chrono::system_clock::now();
    }
    
    /**
     * @brief 玩家升级
     */
    void levelUp() {
        currentPlayer_.level++;
        currentPlayer_.maxHealth += 20;
        currentPlayer_.health = currentPlayer_.maxHealth;
        currentPlayer_.maxMana += 10;
        currentPlayer_.mana = currentPlayer_.maxMana;
        std::cout << "🎉 " << currentPlayer_.name << " 升级到 " 
                  << currentPlayer_.level << " 级!" << std::endl;
    }
    
    /**
     * @brief 获得经验
     */
    void gainExperience(int exp) {
        currentPlayer_.experience += exp;
        std::cout << "获得 " << exp << " 点经验" << std::endl;
    }
    
    /**
     * @brief 添加物品
     */
    void addItem(const std::string& item) {
        currentPlayer_.inventory.push_back(item);
        std::cout << "获得物品: " << item << std::endl;
    }
    
    /**
     * @brief 移动位置
     */
    void moveTo(const std::string& location) {
        currentPlayer_.currentLocation = location;
        currentWorld_.discoveredLocations[location] = true;
        std::cout << "移动到: " << location << std::endl;
    }
    
    /**
     * @brief 完成任务
     */
    void completeQuest(const std::string& questName) {
        currentWorld_.completedQuests[questName] = true;
        std::cout << "完成任务: " << questName << std::endl;
    }
    
    /**
     * @brief 创建存档
     */
    std::shared_ptr<GameSaveMemento> createSave(const std::string& saveName) {
        updatePlayTime();
        std::string desc = currentPlayer_.name + " Lv." + 
                          std::to_string(currentPlayer_.level) + " - " +
                          currentPlayer_.currentLocation;
        return std::make_shared<GameSaveMemento>(
            currentPlayer_, currentWorld_, saveName, desc);
    }
    
    /**
     * @brief 从存档恢复
     */
    void loadFromSave(std::shared_ptr<GameSaveMemento> save) {
        currentPlayer_ = save->getPlayerState();
        currentWorld_ = save->getWorldState();
        sessionStart_ = std::chrono::system_clock::now();
        std::cout << "已加载存档: " << save->getSaveName() << std::endl;
    }
    
    /**
     * @brief 显示当前状态
     */
    void displayStatus() const {
        std::cout << "\n=== 当前游戏状态 ===" << std::endl;
        currentPlayer_.display();
        currentWorld_.display();
        std::cout << "===================" << std::endl;
    }
    
private:
    void updatePlayTime() {
        auto now = std::chrono::system_clock::now();
        auto sessionDuration = std::chrono::duration_cast<std::chrono::seconds>(
            now - sessionStart_);
        currentWorld_.totalPlayTime += sessionDuration.count();
        sessionStart_ = now;
    }
};

/**
 * @brief 存档管理器
 * 
 * 管理多个存档槽位,支持快速保存和加载
 */
class SaveManager {
private:
    std::map<std::string, std::shared_ptr<GameSaveMemento>> saveSlots_;
    std::shared_ptr<GameSaveMemento> quickSave_;
    
public:
    /**
     * @brief 保存到指定槽位
     */
    void saveToSlot(const std::string& slotName, 
                   std::shared_ptr<GameSaveMemento> save) {
        saveSlots_[slotName] = save;
        std::cout << "💾 已保存到槽位: " << slotName << std::endl;
    }
    
    /**
     * @brief 从槽位加载
     */
    std::shared_ptr<GameSaveMemento> loadFromSlot(const std::string& slotName) {
        auto it = saveSlots_.find(slotName);
        if (it != saveSlots_.end()) {
            std::cout << "📂 从槽位加载: " << slotName << std::endl;
            return it->second;
        }
        std::cout << "❌ 槽位不存在: " << slotName << std::endl;
        return nullptr;
    }
    
    /**
     * @brief 快速保存
     */
    void quickSave(std::shared_ptr<GameSaveMemento> save) {
        quickSave_ = save;
        std::cout << "⚡ 快速保存完成" << std::endl;
    }
    
    /**
     * @brief 快速加载
     */
    std::shared_ptr<GameSaveMemento> quickLoad() {
        if (quickSave_) {
            std::cout << "⚡ 快速加载完成" << std::endl;
            return quickSave_;
        }
        std::cout << "❌ 没有快速存档" << std::endl;
        return nullptr;
    }
    
    /**
     * @brief 列出所有存档
     */
    void listSaves() const {
        std::cout << "\n=== 存档列表 ===" << std::endl;
        for (const auto& pair : saveSlots_) {
            std::cout << "槽位: " << pair.first 
                      << " - " << pair.second->getDescription() << std::endl;
        }
        if (quickSave_) {
            std::cout << "快速存档: " << quickSave_->getDescription() << std::endl;
        }
        std::cout << "================" << std::endl;
    }
};

// 演示代码
int main() {
    std::cout << "🎮 游戏存档系统演示" << std::endl;
    std::cout << "===================" << std::endl;
    
    // 创建游戏会话和存档管理器
    GameSession game("冒险者");
    SaveManager saveManager;
    
    // 显示初始状态
    game.displayStatus();
    
    // 进行一些游戏操作
    std::cout << "\n--- 游戏进程 ---" << std::endl;
    game.gainExperience(100);
    game.levelUp();
    game.addItem("魔法杖");
    game.moveTo("黑暗森林");
    game.completeQuest("森林探险");
    
    game.displayStatus();
    
    // 保存游戏
    std::cout << "\n--- 存档操作 ---" << std::endl;
    auto save1 = game.createSave("存档1");
    saveManager.saveToSlot("slot1", save1);
    
    // 继续游戏
    std::cout << "\n--- 继续游戏 ---" << std::endl;
    game.gainExperience(50);
    game.addItem("稀有宝石");
    game.moveTo("龙之巢穴");
    
    game.displayStatus();
    
    // 快速保存
    auto quickSave = game.createSave("快速存档");
    saveManager.quickSave(quickSave);
    
    // 列出所有存档
    saveManager.listSaves();
    
    // 从槽位加载
    std::cout << "\n--- 读档操作 ---" << std::endl;
    auto loadedSave = saveManager.loadFromSlot("slot1");
    if (loadedSave) {
        game.loadFromSave(loadedSave);
        game.displayStatus();
    }
    
    return 0;
}

4.3 Makefile构建配置

makefile 复制代码
# 编译器设置
CXX := g++
CXXFLAGS := -std=c++17 -Wall -Wextra -O2 -g
TARGET := memento_demo
SRCS := text_editor.cpp game_save.cpp main.cpp

# 默认目标
all: $(TARGET)

# 链接目标文件
$(TARGET): $(SRCS:.cpp=.o)
	$(CXX) $(CXXFLAGS) -o $@ $^

# 编译源文件
%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

# 清理生成文件
clean:
	rm -f *.o $(TARGET)

# 运行演示
run: $(TARGET)
	./$(TARGET)

# 调试编译
debug: CXXFLAGS += -DDEBUG -Og
debug: $(TARGET)

# 发布编译
release: CXXFLAGS += -DNDEBUG -O3
release: clean $(TARGET)

# 内存检查
memcheck: $(TARGET)
	valgrind --leak-check=full ./$(TARGET)

# 性能分析
profile: CXXFLAGS += -pg
profile: clean $(TARGET)
	./$(TARGET)
	gprof $(TARGET) gmon.out > analysis.txt

.PHONY: all clean run debug release memcheck profile

4.4 编译与运行指南

编译方法

bash 复制代码
# 1. 基础编译
make

# 2. 调试模式(包含调试信息)
make debug

# 3. 发布模式(优化性能)
make release

# 4. 内存检查
make memcheck

# 5. 性能分析
make profile

运行结果解读

复制代码
🖊️ 高级文本编辑器演示
====================
初始状态:
文档: 测试文档
内容: 
长度: 0 字符
光标: 行 0, 列 0
---
执行编辑操作...
文档: 测试文档
内容: 你好,这是一个备忘录模式的演示。
长度: 24 字符
光标: 行 0, 列 24
---
执行撤销操作...
文档: 测试文档
内容: 你好,这是一个备忘录模式的演示。
长度: 24 字符
光标: 行 0, 列 24
---
历史记录:
0: 插入文本: 你好,这是一个备忘录模式的演示。 @24字符
1: 插入文本: 我们正在测试撤销和重做功能。 @47字符

结果分析

  • ✅ 成功实现了多级撤销/重做功能
  • ✅ 状态保存和恢复正确工作
  • ✅ 历史记录管理有效
  • ✅ 封装性得到保护

5. 高级主题与最佳实践

5.1 性能优化策略

增量状态保存
cpp 复制代码
/**
 * @brief 增量备忘录
 * 
 * 只保存状态变化的部分,减少内存使用
 */
class DeltaMemento : public Memento {
private:
    std::shared_ptr<Memento> baseState_;
    StateDifference delta_;
    std::chrono::system_clock::time_point timestamp_;
    
public:
    DeltaMemento(std::shared_ptr<Memento> base, const StateDifference& delta)
        : baseState_(base), delta_(delta) {
        timestamp_ = std::chrono::system_clock::now();
    }
    
    // 应用差异到基础状态来重建完整状态
    CompleteState reconstructState() const {
        auto base = baseState_->getState();
        return applyDelta(base, delta_);
    }
};
压缩存储
cpp 复制代码
/**
 * @brief 压缩备忘录
 * 
 * 使用压缩算法减少存储空间
 */
class CompressedMemento : public Memento {
private:
    std::vector<uint8_t> compressedData_;
    
    std::vector<uint8_t> compress(const CompleteState& state) {
        // 使用zlib或其他压缩库
        return compressData(serializeState(state));
    }
    
    CompleteState decompress() const {
        return deserializeState(decompressData(compressedData_));
    }
};

5.2 分布式系统应用

在微服务架构中,备忘录模式可以用于实现分布式事务的补偿操作:

cpp 复制代码
/**
 * @brief 分布式事务备忘录
 * 
 * 保存分布式操作的状态,支持补偿事务
 */
class DistributedTransactionMemento : public Memento {
private:
    struct ServiceOperation {
        std::string serviceName;
        std::string operation;
        std::string parameters;
        std::string compensation;
        bool completed;
    };
    
    std::vector<ServiceOperation> operations_;
    std::string transactionId_;
    
public:
    void addOperation(const std::string& service, const std::string& op,
                     const std::string& params, const std::string& comp) {
        operations_.push_back({service, op, params, comp, false});
    }
    
    void markCompleted(size_t index) {
        if (index < operations_.size()) {
            operations_[index].completed = true;
        }
    }
    
    // 执行补偿操作回滚事务
    void compensate() {
        for (auto it = operations_.rbegin(); it != operations_.rend(); ++it) {
            if (it->completed) {
                executeCompensation(it->serviceName, it->compensation);
            }
        }
    }
};

6. 模式对比与选择指南

6.1 相关模式对比

模式 目的 与备忘录模式的关系
命令模式 封装操作请求 命令模式可以结合备忘录实现可撤销的操作
原型模式 通过克隆创建对象 原型模式克隆整个对象,备忘录只保存状态
状态模式 封装状态相关行为 状态模式关注行为,备忘录模式关注状态保存

6.2 选择决策树

复制代码
是否需要保存对象状态?
    ├── 是 → 状态是否简单?
    │   ├── 是 → 考虑直接序列化
    │   └── 否 → 需要保护封装性?
    │       ├── 是 → 使用备忘录模式 ✅
    │       └── 否 → 考虑其他方法
    └── 否 → 不需要备忘录模式

7. 总结

备忘录模式是一个强大而优雅的设计模式,它完美地解决了状态保存与封装性保护之间的矛盾。通过本文的深度解析,我们可以看到:

核心价值

  • 🛡️ 封装性保护:在不暴露内部细节的前提下保存状态
  • 🔄 状态管理:提供完整的状态保存和恢复机制
  • 🎯 职责清晰:明确的角色分离和职责划分

实现要点

  • 合理使用友元关系保护备忘录内容
  • 选择适当的状态存储策略(完整/增量)
  • 实现健壮的历史记录管理
  • 考虑性能和内存使用优化

适用场景

  • 文本编辑器的撤销/重做功能
  • 游戏存档系统
  • 事务回滚机制
  • 配置保存和恢复
  • 任何需要"时间旅行"功能的系统

备忘录模式不仅是技术实现,更是一种设计哲学的体现:在复杂系统中为用户提供"后悔"的权利,让交互更加友好和可靠。掌握这个模式,你将能够构建出更加健壮和用户友好的软件系统。

相关推荐
小张成长计划..2 小时前
STL简介
c++
CHANG_THE_WORLD2 小时前
函数简单传入参数的汇编分析
汇编·c++·算法
HalvmånEver4 小时前
初学者入门 C++ map 容器:从基础用法到实战案例
开发语言·c++·学习·map
saber_andlibert4 小时前
【C++】——new和delete与malloc和free的区别
c语言·c++
维度攻城狮5 小时前
C++中的多线程编程及线程同步
开发语言·c++·性能优化·多线程·线程同步
拾光Ծ5 小时前
【C++哲学】面向对象的三大特性之 多态
开发语言·c++·面试
小欣加油5 小时前
leetcode 494 目标和
c++·算法·leetcode·职场和发展·深度优先
大飞pkz5 小时前
【设计模式】解释器模式
开发语言·设计模式·c#·解释器模式
Miki Makimura5 小时前
基于网络io的多线程TCP服务器
网络·c++·学习