首页 智能家居

C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南

分类:智能家居
字数: (8414)
阅读: (3916)
内容摘要:C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南,

在复杂的 C++ 项目中,经常会遇到需要保存对象状态并在未来某个时间点恢复的情况。比如,文本编辑器的撤销功能,游戏角色的状态回溯,数据库事务的回滚等等。如果没有一种优雅的方式来管理这些状态,代码将会变得难以维护和测试。这时候,备忘录模式就能派上用场了。本文将深入剖析 C++ 中备忘录模式的底层原理,并结合具体代码示例,分享实战中避免踩坑的经验。

问题场景重现:文本编辑器的撤销功能

想象一下,你正在开发一个简单的文本编辑器。用户可以输入文字、删除文字,但是希望能够随时撤销之前的操作。如果没有备忘录模式,你可能需要维护一个巨大的操作历史列表,每次撤销都要遍历这个列表,效率低下且容易出错。

C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南

底层原理深度剖析

备忘录模式的核心思想是将对象的状态保存到独立的备忘录对象中,并在需要的时候从备忘录对象中恢复状态。它涉及三个主要角色:

C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南
  • 发起人 (Originator):负责创建备忘录,并在需要时从备忘录中恢复自身状态。
  • 备忘录 (Memento):存储发起人的内部状态,防止发起人以外的其他对象访问。
  • 管理者 (Caretaker):负责保存和提供备忘录,但不负责查看备忘录的内容。

这种设计模式的关键在于隔离了状态的存储和恢复逻辑,使得发起人可以专注于自身业务,而不用关心状态的细节。它有点像 Nginx 的反向代理服务器,客户端(Caretaker)只负责发起请求,Nginx(Originator)负责处理请求并生成响应(Memento),缓存服务器(另一种 Memento)负责保存响应,并在下次请求时直接返回,提高性能。

C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南

具体的代码解决方案

下面是一个简单的 C++ 示例,演示如何使用备忘录模式实现文本编辑器的撤销功能:

C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南
#include <iostream>
#include <string>
#include <vector>

class Editor {
private:
  std::string text;

public:
  void setText(const std::string& newText) {
    text = newText;
  }

  std::string getText() const {
    return text;
  }

  class Memento {  // 备忘录类,Editor的内部类
  private:
    std::string text;

  public:
    Memento(const std::string& text) : text(text) {}

    std::string getText() const {
      return text;
    }
  };

  Memento save() {
    return Memento(text); // 创建备忘录,保存当前状态
  }

  void restore(const Memento& memento) {
    text = memento.getText(); // 从备忘录恢复状态
  }
};

class History {
private:
  std::vector<Editor::Memento> history;

public:
  void push(const Editor::Memento& memento) {
    history.push_back(memento);
  }

  Editor::Memento pop() {
    Editor::Memento memento = history.back();
    history.pop_back();
    return memento;
  }
  bool isEmpty() const{
    return history.empty();
  }
};

int main() {
  Editor editor;
  History history;

  editor.setText("Hello");
  history.push(editor.save());

  editor.setText("Hello World");
  history.push(editor.save());

  std::cout << "Current Text: " << editor.getText() << std::endl; // Output: Current Text: Hello World

  editor.restore(history.pop());

  std::cout << "Previous Text: " << editor.getText() << std::endl; // Output: Previous Text: Hello

  if(!history.isEmpty()){
    editor.restore(history.pop());
    std::cout << "Original Text: " << editor.getText() << std::endl; // Output: Original Text: Hello
  } else {
    std::cout << "No more undo available."<<std::endl;
  }



  return 0;
}

在这个例子中,Editor 类是发起人,Editor::Memento 类是备忘录,History 类是管理者。Editor 类负责保存和恢复文本内容,History 类负责存储备忘录,并提供撤销功能。

实战避坑经验总结

  • 慎用深拷贝:在创建备忘录时,应该根据实际情况选择浅拷贝或深拷贝。如果状态对象包含大量数据,深拷贝会消耗大量内存和时间。如果状态对象是不可变的,浅拷贝就足够了。
  • 保护备忘录:备忘录对象应该对发起人以外的其他对象隐藏其内部状态。可以使用访问控制修饰符(如 private)或设计模式(如窄接口)来实现。
  • 考虑并发安全:如果在多线程环境中使用备忘录模式,需要考虑并发安全问题。可以使用互斥锁或其他同步机制来保护状态对象和备忘录。
  • 避免备忘录膨胀:如果状态变化非常频繁,可能会导致备忘录数量过多,占用大量内存。可以考虑定期清理过期的备忘录,或者使用增量备忘录,只保存状态的变化部分。

例如,在处理高并发请求的 Nginx 服务中,如果频繁地创建和销毁备忘录,会导致大量的内存碎片,影响性能。这时,可以考虑使用对象池来复用备忘录对象,或者使用 copy-on-write 技术来减少拷贝开销。

总结来说,备忘录模式是一种非常有用的设计模式,可以帮助我们更好地管理对象状态,提高代码的可维护性和可测试性。但是,在使用时需要注意一些细节,避免踩坑。希望本文能够帮助你更好地理解和应用备忘录模式。

C++ 设计模式探秘:备忘录模式的原理、实现与避坑指南

转载请注明出处: 代码一只喵

本文的链接地址: http://m.acea2.store/article/21818.html

本文最后 发布于2026-04-23 19:31:13,已经过了4天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • e人代表 1 天前
    增量备忘录是个好主意,可以避免内存占用过高。有没有具体的实现方案可以参考一下?
  • 铲屎官 3 天前
    不错,用内部类实现备忘录是个好思路。
  • 社恐患者 3 天前
    不错,用内部类实现备忘录是个好思路。