备忘录设计模式 vs 版本设计模式

📘 备忘录设计模式 vs 版本设计模式

引用

  1. 世人痴情无数 如戏一出 唱韶华莫负
  2. 叹此红尘阎浮 为何偏作相思骨 且把酒 拂花遥相祝

🧩 一、核心概念与设计思想

🔮 1. 备忘录模式(Memento Pattern)

设计思想状态封装 + 外部存储

  • 核心目标:在不破坏对象封装性的前提下,捕获并存储其内部状态,支持状态回滚。
  • 三元素模型
    creates stores Originator +SetState() +CreateMemento() +RestoreMemento(m: Memento) Memento -state: string +GetState() Caretaker -memento: Memento +Save(m: Memento) +Retrieve()
  • 思想重点
    • 封装性保护:Memento仅对Originator暴露完整状态,Caretaker无法直接修改状态。
    • 单一快照:每次保存独立状态快照,无历史关联性。
🔁 2. 版本模式(Versioning Pattern)

设计思想历史链 + 增量管理

  • 核心目标:维护对象所有历史状态记录,支持任意历史版本回溯和比较。
  • 链式存储模型
    contains * Document -content: string -versionHistory: Version* +CommitVersion(version: Version) +GetVersion(vId: int) Version -id: int -timestamp: time -delta: string // 变化量 +ApplyDelta()
  • 思想重点
    • 版本关联:版本间通过增量(delta)链接,形成时间线。
    • 高效存储:仅存储变化量而非全量数据,降低内存占用。

⚙️ 二、C++实现对比

📂 1. 备忘录模式实现
cpp 复制代码
#include <iostream>  
#include <string>  
#include <vector>  

class Memento {  
private:  
    std::string state;  
    friend class Originator; // 仅允许Originator访问  
    Memento(const std::string& s) : state(s) {}  
    std::string GetState() const { return state; }  
};  

class Originator {  
private:  
    std::string state;  
public:  
    void SetState(const std::string& s) { state = s; }  
    Memento* CreateMemento() { return new Memento(state); }  
    void RestoreMemento(const Memento* m) { state = m->GetState(); }  
    void Print() { std::cout << "Current State: " << state << std::endl; }  
};  

class Caretaker {  
private:  
    std::vector<Memento*> history;  
public:  
    void Save(Memento* m) { history.push_back(m); }  
    Memento* Retrieve(int index) { return history[index]; }  
};  

// 使用示例  
int main() {  
    Originator editor;  
    Caretaker history;  

    editor.SetState("Version1");  
    history.Save(editor.CreateMemento());  
    editor.Print(); // Output: Version1  

    editor.SetState("Version2");  
    history.Save(editor.CreateMemento());  

    editor.RestoreMemento(history.Retrieve(0));  
    editor.Print(); // Output: Version1 (回滚成功)  
}  

关键点

  • Memento构造函数私有,仅Originator可创建。
  • Caretaker存储历史快照,但无法修改内容。
🔗 2. 版本模式实现
cpp 复制代码
#include <iostream>  
#include <string>  
#include <vector>  
#include <ctime>  

class Version {  
public:  
    int id;  
    time_t timestamp;  
    std::string delta; // 存储变化量  
    Version(int vId, const std::string& d) : id(vId), delta(d) {  
        timestamp = time(nullptr);  
    }  
};  

class Document {  
private:  
    std::string content;  
    std::vector<Version*> history;  
public:  
    void AppendContent(const std::string& text) {  
        Version* v = new Version(history.size()+1, text);  
        history.push_back(v);  
        content += text; // 应用新内容  
    }  
    void RevertToVersion(int vId) {  
        content = ""; // 重建历史  
        for (int i=0; i<=vId; ++i) {  
            content += history[i]->delta;  
        }  
    }  
    void PrintHistory() {  
        for (auto& v : history) {  
            std::cout << "v" << v->id << " at " << v->timestamp << std::endl;  
        }  
    }  
};  

// 使用示例  
int main() {  
    Document doc;  
    doc.AppendContent("Hello");  
    doc.AppendContent(" World");  
    doc.PrintHistory();  
    doc.RevertToVersion(0); // 回退到"Hello"  
}  

关键点

  • 使用delta存储增量变化,非全量数据。
  • 版本号(id)和时间戳用于追踪历史。

🔍 三、核心差异对比

维度 备忘录模式 版本模式
状态存储方式 全量快照 增量(delta)链式存储
历史关联性 无版本关联 显式版本链(时间线)
封装性保护 严格(仅Originator可操作Memento) 弱(Document直接管理Version)
内存效率 低(全量存储) 高(仅存变化量)
回溯灵活性 仅支持离散快照回滚 支持任意版本跳跃

🎯 四、适用场景与优劣分析

📌 1. 备忘录模式

✅ 适用场景

  • 需要回滚操作的场景(如编辑器撤销、游戏存档)。
  • 需严格保护对象内部状态的系统(如金融事务快照)。
  • 状态变化频率较低的场景。

⛔ 缺点

  • 内存占用高:每个快照存储全量数据。
  • 历史关联弱:无法追踪状态变化路径。
📊 2. 版本模式

✅ 适用场景

  • 需详细历史追踪的系统(如Git版本控制、文档协同编辑)。
  • 高频状态变化的场景(如实时协作白板)。
  • 需要版本比较/分支管理的应用。

⛔ 缺点

  • 实现复杂度高:需设计增量存储和重建逻辑。
  • 回滚性能问题:版本链越长,重建越耗时。

🔬 五、设计思想深度剖析

🧠 1. 状态管理哲学
  • 备忘录模式状态即孤岛

    • 每个快照独立存在,无上下文依赖。
    • 符合"隔离性"设计原则(如事务的ACID特性)。
  • 版本模式状态即时间流

    • 状态是历史累积的结果。
    • 强调因果关联性,符合事件溯源(Event Sourcing)思想。
💡 2. 性能与存储权衡
模式 存储成本 恢复成本
备忘录模式 O(n) * 全量大小 O(1)(直接替换)
版本模式 O(n) * 变化量大小 O(k)(k为目标版本)

🏁 六、总结

维度 备忘录模式 版本模式
核心思想 状态隔离快照 历史版本链
最佳应用 撤销操作、事务回滚 版本控制、协同编辑
扩展性 低(新增状态需全量保存) 高(增量存储易扩展)
系统影响 内存敏感型系统慎用 CPU敏感型系统慎用(重建成本高)

📌 设计决策建议

  • 选择备忘录模式当:需严格封装状态 + 回滚需求简单 + 内存充足。
  • 选择版本模式当:需完整历史追溯 + 内存优化优先 + 可接受重建开销。
相关推荐
PAK向日葵37 分钟前
【算法导论】MT 0823笔试题题解
算法·面试
Yolo566Q1 小时前
“R语言+遥感”的水环境综合评价方法实践技术应用
开发语言·r语言
智驱力人工智能1 小时前
安全帽检测算法如何提升工地安全管理效率
人工智能·算法·安全·边缘计算·安全帽检测·口罩检测·安全鞋检测
艾莉丝努力练剑1 小时前
【C语言16天强化训练】从基础入门到进阶:Day 6
c语言·数据结构·学习·算法
快去睡觉~2 小时前
力扣1005:k次取反后最大化的数组和
数据结构·算法·leetcode
smilejingwei2 小时前
数据分析编程第二步: 最简单的数据分析尝试
数据库·算法·数据分析·esprocspl
文火冰糖的硅基工坊3 小时前
[激光原理与应用-317]:光学设计 - Solidworks - 草图
开发语言·python·信息可视化·系统架构
草莓熊Lotso3 小时前
【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day10
c语言·开发语言·经验分享·算法·强化
草明3 小时前
docker stats 增加一列容器名称的显示
java·开发语言·docker
He1955013 小时前
Go初级二
开发语言·后端·golang