C++设计模式——备忘录模式

设计模式C++实现(12)——备忘录模式 软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书,对于每个模式,用C++写了个小例子,加深一下理解。主要参考《大 阅读详情

备忘录模式

在GOF的《设计模式:可复用面向对象软件的基础》一书中对备忘录模式是这样说的:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制,而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到它们先前的状态。如何实现这个将状态信息保存在某处呢?使用原型模式?由于对象通常封装了其部分或所有的状态信息,使得其状态不能被其他对象访问,也就不可能在该对象之外保存其状态了。由于原型模式总是返回对象的全部状态信息,同时原型模式使其状态能被其它对象访问,这样就违反了封装的原则,还可能有损应用的可靠性和可扩展性。

再拿上面的《仙剑奇侠传》进行分析,当我们在打大BOSS之前存档,此时就需要将对应的游戏场景,任务信息,人物信息等等状态存储起来;当赢得大BOSS之后,覆盖之前的存档时,就将之前的存档丢弃,新建立一个存档,保存当前的状态信息;如果打输了,恢复存档,就将之前的存档信息读取出来,还原到打大BOSS之前的游戏场景,重新开始打大BOSS。这里面就是使用的备忘录模式。

一个备忘录是一个对象,它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器。当需要设置原发器的检查点时,取消操作机制会向原发器请求一个备忘录。原发器用描述当前状态的信息初始化该备忘录。只有原发器可以向备忘录中存取信息,备忘录对其他的对象是“不可见”的。

 

UML类图

Memento:备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态;防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者只能看到备忘录的窄接口————它只能将备忘录传递给其他对象。相反,原发器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生成备忘录的那个原发器访问本备忘录的内部状态;
Originator:原发器创建一个备忘录,用以记录当前时刻它的内部状态;我们使用备忘录恢复内部状态;
Caretaker:负责保存好备忘录;但是,不能对备忘录的内容进行操作或检查。

备忘录模式是按照以下方式进行协作的:
管理器向原发器请求一个备忘录,保留一段时间后,将其送回给原发器;而有的时候管理者不会将备忘录返回给原发器,因为原发器可能根本不需要退到先前的状态。备忘录是被动的,只有创建备忘录的原发器会对它的状态进行赋值和检索,如下面的时序图:

 

使用场合

在以下情况下使用备忘录模式:

  1. 必须保存一个对象在某一个时刻的部分或完整状态,这样以后需要时它才能恢复到先前的状态;
  2. 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

 

代码实现

#include <iostream>
using namespace std;

struct State
{
     wchar_t wcsState[260];
};

class Memento
{
public:
     Memento(State *pState) : m_pState(pState){}

     State *GetState() { return m_pState; }

private:
     friend class Originator;

     State *m_pState;
};

class Originator
{
public:
     Originator() : m_pState(NULL) {}
     ~Originator()
     {
          // Delete the storage of the state
          if (m_pState)
          {
               delete m_pState;
               m_pState = NULL;
          }
     }

     void SetMemento(Memento *pMemento);
     Memento *CreateMemento();

     void SetValue(wchar_t *value)
     {
          memset(wcsValue, 0, 260 * sizeof(wchar_t));
          wcscpy_s(wcsValue, 260, value);
     }

     void PrintState() { wcout<<wcsValue<<endl; }

private:
     State *m_pState; // To store the object's state

     wchar_t wcsValue[260]; // This is the object's real data
};

Memento *Originator::CreateMemento()
{
     m_pState = new State;
     if (m_pState == NULL)
     {
          return NULL;
     }

     Memento *pMemento = new Memento(m_pState);

     wcscpy_s(m_pState->wcsState, 260, wcsValue); // Backup the value
     return pMemento;
}

void Originator::SetMemento(Memento *pMemento)
{
     m_pState = pMemento->GetState();

     // Recovery the data
     memset(wcsValue, 0, 260 * sizeof(wchar_t));
     wcscpy_s(wcsValue, 260, m_pState->wcsState);
}

// Manager the Memento
class Caretaker
{
public:
     Memento *GetMemento() { return m_pMemento; }
     void SetMemnto(Memento *pMemento)
     {
          // Free the previous Memento
          if (m_pMemento)
          {
               delete m_pMemento;
               m_pMemento = NULL;
          }

          // Set the new Memento
          m_pMemento = pMemento;
     }

private:
     Memento *m_pMemento;
};

int main()
{
     Originator *pOriginator = new Originator();
     pOriginator->SetValue(L"On");
     pOriginator->PrintState();

     // Now I backup the state
     Caretaker *pCaretaker = new Caretaker();
     pCaretaker->SetMemnto(pOriginator->CreateMemento());

     // Set the new state
     pOriginator->SetValue(L"Off");
     pOriginator->PrintState();

     // Recovery to the old state
     pOriginator->SetMemento(pCaretaker->GetMemento());
     pOriginator->PrintState();

     if (pCaretaker)
     {
          delete pCaretaker;
     }

     if (pOriginator)
     {
          delete pOriginator;
     }

     return 0;
}

我再根据上面的《仙剑奇侠传》来完成备忘录模式,代码如下:

#include <iostream>
using namespace std;

class RoleStateMemento
{
public:
     RoleStateMemento(unsigned iBlood, unsigned iAttack, unsigned iDefense) : m_iBlood(iBlood), m_iAttack(iAttack), m_iDefense(iDefense){}

private:
     friend class GameRole;

     unsigned GetBloodValue() { return m_iBlood; }
     unsigned GetAttackValue() { return m_iAttack; }
     unsigned GetDefenseValue() { return m_iDefense; }

     unsigned m_iBlood;   // 生命力
     unsigned m_iAttack;  // 攻击力
     unsigned m_iDefense; // 防御力
};

class GameRole
{
public:
     GameRole() : m_iBlood(100), m_iAttack(100), m_iDefense(100){}

     // 存档
     RoleStateMemento *SaveState() { return new RoleStateMemento(m_iBlood, m_iAttack, m_iDefense); }

     // 恢复存档
     void RecoveryState(RoleStateMemento *pRoleState)
     {
          m_iBlood = pRoleState->GetBloodValue();
          m_iAttack = pRoleState->GetAttackValue();
          m_iDefense = pRoleState->GetDefenseValue();
          cout<<"Recovery..."<<endl;
     }

     void ShowState()
     {
          cout<<"Blood:"<<m_iBlood<<endl;
          cout<<"Attack:"<<m_iAttack<<endl;
          cout<<"Defense:"<<m_iDefense<<endl;
     }

     void Fight()
     {
          m_iBlood -= 100;
          m_iAttack -= 10;
          m_iDefense -= 20;

          if (m_iBlood == 0)
          {
               cout<<"Game Over"<<endl;
          }
     }

private:
     unsigned m_iBlood;   // 生命力
     unsigned m_iAttack;  // 攻击力
     unsigned m_iDefense; // 防御力
};

class RoleStateCaretaker
{
public:
     void SetRoleStateMemento(RoleStateMemento *pRoleStateMemento) { m_pRoleStateMemento = pRoleStateMemento; }
     RoleStateMemento *GetRoleStateMemento() { return m_pRoleStateMemento; }

private:
     RoleStateMemento *m_pRoleStateMemento;
};

int main()
{
     GameRole *pLiXY = new GameRole(); // 创建李逍遥这个角色
     pLiXY->ShowState(); // 显示初始的状态

     // 存档
     RoleStateCaretaker *pRoleStateCaretaker = new RoleStateCaretaker();
     pRoleStateCaretaker->SetRoleStateMemento(pLiXY->SaveState());

     // 开始打大BOSS
     pLiXY->Fight();
     pLiXY->ShowState();

     // 读档,从新开始
     pLiXY->RecoveryState(pRoleStateCaretaker->GetRoleStateMemento());
     pLiXY->ShowState();

     return 0;
}

总结

备忘录模式在实际应用中也不少;我们在进行文档编辑时,经常使用的撤销操作。使用C++实现备忘录模式的关键点在于Originator类是Memento的友元类,这样就使得管理备忘录的Caretaker对象,以及其它对象都不能读取、设置备忘录,只有Originator类才能进行备忘录的读取和设置。由于备忘录主要是用于对对象的状态进行备份,实现了撤销操作,如果对象的状态数据很大很多时,在进行备忘时,就会很占用资源,这个是我们在实际开发时需要考虑的东西。结合之前的设计模式,在总结命令模式时,说到命令模式支持事物的回退,而这个就是依靠的备忘录模式来实现的。好了,备忘录模式就总结至此。希望对大家有用。

《C++ 设计模式》 设计模式代表了最佳的实践,在面向对象的编程中被很多老鸟们反复使用。使用设计模式有很多好处:可重用代码、保证代码可靠性、使代码更易被他人理解 ...... 阅读详情

相关推荐

告别黑窗口!用VSCode+Native Debug调试C/C++程序,比GDB命令行舒服多了

本文介绍了如何使用VSCode配合Native Debug扩展来调试C/C++程序,替代传统的GDB命令行方式。通过可视化调试环境,开发者可以更高效地管理断点、查看变量和调用栈,大幅提升调试效率。文章详细讲解了环境配置、核心调试功能及高级技巧,帮助开发者快速上手这一现代调试工具。

weixin_26833139的博客 249

C++设计模式(全23种)

设计模式概述 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。等这种思想融入到了思想中后,你就会不自觉地使用这种思想去进行你的设计和开发。 文章目录设计模式概述一、创建型模式Factory 模式(工厂模式)AbstactFactory 模式(抽象工厂模式)Singleton 模式( 单例模式)Builder 模式(建造者模式)Prototype 模式(原型模式)二、结构型模式Bridge 模式(桥接模式)总结

weixin_45712636的博客 9万+

企业微信群机器人配置全攻略:从零到消息推送的完整流程

本文详细介绍了企业微信群机器人的配置与使用全流程,从零开始指导如何创建机器人、获取Webhook地址,到通过HTTP请求发送文本、Markdown、图片及模板卡片等多种消息类型。内容涵盖核心的接口配置、安全实践及实战应用场景,帮助开发与运维团队快速构建自动化消息推送中枢,提升协作效率。

weixin_29231725的博客 836

细数C++的各种设计模式

访问者模式是一种行为型设计模式,它定义了在不改变对象结构的情况下对集合中的元素进行操作的方式。代理模式是一种结构模式,通过在对象之间提供一个代理对象来控制对象的访问。命令模式是一种行为型模式,将请求封装成对象,使得可以使用不同的请求、日志、事务和支持撤销操作的操作来对请求进行参数化。模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,允许子类重写特定方法的实现,而不改变算法的结构。观察者模式是一种行为型模式,用于在对象之间定义一对多的依赖关系,以便当对象的状态发生改变时通知其他对象。

2301_78032663的博客 2571

matsim教程及其案例

MATSim 是一个强大的交通仿真工具,适合研究交通政策、出行行为优化和城市规划。建议从官方示例入手,逐步尝试修改参数和扩展功能。遇到问题时,优先查阅官方文档和社区讨论。(Multi-Agent Transport Simulation Toolkit)的教程和案例资源整理,涵盖基础入门、核心概念、实际应用案例及学习路径。MATSim 是一个开源的、基于多智能体的交通仿真框架,用于模拟城市交通系统中的出行行为、交通流量和交通政策影响。

weixin_70682362的博客 1092

DSShop移动商城网店系统 反序列化RCE漏洞复现

DSShop单店铺移动商城网店系统的getCartList方法的cart参数存在php反序列化漏洞,攻击者可以通过漏洞执行任意代码,获取服务器权限。

0xSec 1471

C++ 常用设计模式(学习笔记)

设计模式 1、工厂模式 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。工厂模式作为一种创建模式,一般在创建复杂对象时,考虑使用;在创建简单对象时,建议直接new完成一个实例对象的创建。 1.1、简单工厂模式 主要特点是需要在工厂类中做判断,从而创造相应的产品,当增加新产品时,需要修改工厂类。使用简单工厂模式,我们只需要知道具体的产品型号就可...

duchengjun的博客 1910

基于STM32的室内环境监测系统设计与实现

摘要 本文设计了一种基于STM32的室内环境监测系统,通过传感器实时采集温湿度、空气质量、烟雾浓度等数据,并利用Wi-Fi模块上传至云服务器。系统采用STM32F103C8T6作为主控芯片,结合DHT11、MQ系列传感器及BMP280气压传感器实现数据采集,通过ESP8266模块实现远程数据传输。用户可通过手机APP实时查看环境参数,并在数据超标时触发报警。实验表明,系统运行稳定,监测精度高,具有低成本、易扩展等特点,为改善室内环境质量提供了有效解决方案。 关键词:STM32;室内环境监测;传感器;Wi-F

3254968421的博客 221

C++设计模式总结

一、单例模式 一个类不管常见多少次对象,永远只能得到该类型一个对象的实例 // p1、p2、p3指向同一对象 A* p1 = new A(); A* p2 = new A(); A* p3 = new A(); 饿汉式单例模式: 还没有获取实例对象,实例对象就已经产生了 优点:线程安全。对象存放在数据段,main函数还没有开始执行,对象就已经初始化好了,一定是线程安全的。 缺点: 获取在软件启动的时候,并没有使用到这个对象,然而这个对象已经产生,这就比较浪费资源。 #include<iostream

长期更新自学笔记 5246

Fastgpt本地使用Docker Compose 快速部署

修改文件,并执行再执行d重起容器。具体配置,参考配置详解。可以查看日志,在启动容器后,第一次请求网页,会进行配置文件读取,可以看看有没有读取成功以及有无错误日志。进入 FastGPT 容器,可以通过ls data查看目录下是否成功挂载文件。可通过查看配置文件。可能不生效的原因挂载目录不正确配置文件不正确,日志中会提示invalid json,配置文件需要是标准的 JSON 文件。

洛阳泰山的博客 1630

【Python基础】FastAPI 从入门到项目实战操作详解

【Python基础】FastAPI从入门到使用实战操作详解

congge_study的博客 434

C++设计模式——备忘录模式(Memento Pattern)

C++设计模式——备忘录模式(Memento Pattern) 微信公众号:幼儿园的学霸 目录 文章目录C++设计模式——备忘录模式(Memento Pattern)目录定义代码示例总结参考资料 定义 Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later 在不破坏封装性的前提下,捕

leonardohaig的博客 1006

ABAP BDC 处理踩坑笔记:把错误挡在录制之前,把稳定做进每一行 BDCDATA

本文总结了SAP BDC(批输入)开发中的常见问题和解决方案。重点包括:1)理解BDCDATA本质是模拟人工操作而非直接操作数据库;2)数据格式化技巧,如金额、日期、物料号等字段的标准化处理;3)通过CTU_PARAMS参数控制执行环境,确保屏幕尺寸和更新模式一致;4)不要依赖sy-subrc,应通过解析MESSTAB消息判断业务是否成功;5)录制阶段的常见陷阱及解决方法;6)疑难问题的系统性解决思路;7)建议建立完善的错误处理机制,包括日志记录和重跑功能。文章提供了实用的ABAP代码示例和配置建议,帮助开

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 262

C++设计模式——备忘录模式(memento pattern)

博主看了许多文章和一些书,发现要么代码不全,要么对备忘录的理解有偏差,要么干脆根本就不是备忘录模式,经过博主查阅十余篇文章和详细研究书本备忘录模式,总结出这篇精华的c++备忘录模式文章,感兴趣的朋友可以阅读和提出建议。 # 一、原理讲解 别名Token。 ## 1.1意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

净无邪博客 1482

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

C++设计模式行为模式———备忘录模式

当需要创建对象状态快照来恢复其之前的状态时,可以使用备忘录模式。备忘录模式允许复制对象中的全部状态(包括私有成员变量),并将其独立于对象进行保存。它在处理事务(比如需要在出现错误时回滚一个操作)的过程中也必不可少。可以同时使用命令模式和备忘录模式来实现 “撤销”。在这种情况下, 命令用于对目标对象执行各种不同的操作, 备忘录用来保存一条命令执行前该对象的状态。也可以同时使用备忘录和迭代器模式来获取当前迭代器的状态, 并且在需要的时候进行回滚。其独立于对象进行保存。

无敌岩雀的博客 2054

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++ 设计模式之备忘录模式

对于每个 "Increment" 和 "Decrement" 操作,输出当前计数器的值,计数器数值从0开始 对于每个 "Undo" 操作,输出撤销后的计数器值。输入包含若干行,每行包含一个字符串,表示计数器应用的操作,操作包括 "Increment"、 "Decrement"、"Undo" 和 "Redo"。备忘录有两个接⼝,发起⼈能够通过宽接⼝访问数据,管理者只能看到窄接⼝,并将备忘录传递给其他对象。UndoManager 和UndoableEdit 接⼝是与备忘录模式相关的主要类和接⼝。

K1_uestc的博客 2184

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C++ 设计模式:备忘录模式(Memento Pattern)

C++ 设计模式:备忘录模式(Memento Pattern)

冀晓武的博客 808

【c++设计模式20】行为模式5:备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)是一种行为型设计模式,它通过捕获一个对象的内部状态,并在该对象之外保存这个状态,从而在需要时可以将该对象恢复到原先保存的状态。备忘录模式实现了在不破坏封装性的前提下,对对象的状态进行备份和恢复。

junxuezheng的博客 543

C++设计模式-备忘录模式

目录 基本概念 代码与实例 基本概念 备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将对象恢复到原先保存的状态。 结构图如下(此图来源于大话设计模式): Originator为发起者 Memento为备忘录 Caretaker为管理者 Memento模式比较适用于功能复杂的,但需要维护...

IT1995的博客 4678

23种设计模式C++实例之备忘录模式

【代码】23种设计模式C++实例之备忘录模式。

寒风的技术博客 1222

C++-设计模式-备忘录模式

​ Memento模式也叫备忘录模式,是行为模式之一,它的作用是保存对象的内部状态,并在需要的时候(undo/rollback)恢复对象以前的状态。

Asincereman的专栏 280

C++设计模式——10备忘录模式

#include<iostream> #include<string> #include<vector> using namespace std; class Memento { public: Memento(string state) { this->state = state; } string getState() { r

qq_52553095的博客 326

C++ 设计模式——备忘录模式

备忘录(Memento)模式也称为快照(Snapshot)模式,是一种行为型模式,主要用于防止数据丢失。它通过对对象的状态进行备份,以便在未来需要时可以恢复这些数据。换句话说,该模式能够将某个时间点的对象内部状态保存下来,并在必要时根据保存的内容将该对象恢复到当时的状态。备忘录模式的结构比较简单,使用频率相对较低,但在特定场景下非常有用。

慢慢记录,慢慢更新。 2287

简单易懂23种设计模式——备忘录模式【含C++代码实例】

23种设计模式C++实现——备忘录模式    在做面向对象的软件开发时我们往往想达到更高的代码可复用性和更合理的软件颗粒度。   根据《设计模式——可复用面向对象软件的基础》所说:“你必须找到相关的对象,以适当的颗粒度将他们回归类,再定义类的接口和继承层次,建立对象之间的基本关系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求也要有足够的通用性。”12   内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用的解决方案。这些重复的模式方案解决特定的问题,使得面向对象的设

机器人梦想家 Bing Lee 2937

基于C++的《Head First设计模式》笔记——备忘录模式

本文介绍了备忘录设计模式(Memento Pattern)的概念与实现。该模式用于在不破坏封装性的前提下保存对象内部状态,以便后续恢复。文章通过C++代码展示了图形软件中位置坐标的保存与恢复案例,详细说明了原发器(Originator)、备忘录(Memento)和管理者(Caretaker)三个核心角色的实现方法。备忘录模式的优点包括保持高内聚低耦合、维护数据封装、便于实现撤销功能;缺点是可能因深拷贝导致性能开销。该模式适用于软件撤销/重做、游戏存档等场景,并可结合命令模式实现更灵活的撤销机制。

Yu_Lijing的博客 529

大话设计模式备忘录模式c++实现

备忘录模式 其他二十三种设计模式 #include<iostream> using namespace std; //备忘录模式 //角色状态备忘录类 class RoleStateMemento { public: RoleStateMemento(int _vit,int _atk,int _def) { this->vit = _vit; this->atk = _atk; this->def = _def; } void SetVitality(in

wode_0828的博客 198
上一篇: C++设计模式——中介者模式
下一篇: C++设计模式——观察者模式
CoderAldrich
博客等级 码龄12年 431粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值