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

19行为型设计模式——备忘录模式

一、备忘录模式简介

备忘录模式(Memento Pattern)是一种行为型设计模式,又叫做快照模式,它允许在不破坏对象封装性的前提下捕获并保存一个对象的内部状态,以便在将来能够将对象恢复到原先保存的状态。

GoF一书中对备忘录模式的介绍

  1. Originator(发起人)

    • 负责创建一个备忘录Memento,记录当前时刻的内部状态。
    • 提供创建备忘录和恢复备忘录数据的功能。
    • 可以访问备忘录里的所有信息。
  2. Memento(备忘录)

    • 负责存储Originator的内部状态。
    • 防止Originator以外的对象访问备忘录。
    • 提供接口供Originator获取和设置状态。
  3. Caretaker(管理者)

    • 负责管理备忘录Memento。
    • 不能访问或操作Memento的内容。

二、备忘录模式的设计方法

     使用备忘录模式来管理游戏角色的状态。通过CareTaker类,用户可以保存和恢复角色的状态,从而实现游戏状态的撤销和回滚功能。这个设计模式在需要保存和恢复对象状态的应用中非常有用,例如撤销操作、恢复功能等。

memento.cpp

#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <stdexcept>// 备忘录
class Memento {
public:Memento(int health, int level) : health(health), level(level) {}int getHealth() const { return health; }int getLevel() const { return level; }private:int health;int level;	
};// 游戏角色(Originator)
class GameCharacter {
public:GameCharacter(int health, int level) : health(health), level(level) {}void setHealth(int newHealth) { health = newHealth; }void setLevel(int newLevel) { level = newLevel; }Memento save() const {return Memento(health, level);}void restore(const Memento& memento) {health = memento.getHealth();level = memento.getLevel();}bool SimulateStatus() const {std::cout << "健康值: " << health << ", 等级: " << level << std::endl;return health > 0;}private:int health;int level;
};// 管理者
class CareTaker {
public:void saveMemento(const Memento& memento, size_t index) {undoStack.push({memento, index});rollbackStack.push({memento, index});}void undo(GameCharacter& character) {if (undoStack.empty()) {std::cerr << "没有上一份状态,不需要撤销." << std::endl;return;}MementoData mementoData = undoStack.top();undoStack.pop();rollbackStack.push(mementoData);if (!undoStack.empty()) {MementoData toData = undoStack.top();character.restore(toData.memento);}}void rollback(GameCharacter& character, size_t index) {if (index >= rollbackStack.size()) {std::cerr << "无效的回滚状态." << std::endl;return;}std::stack<MementoData> tempStack;while (rollbackStack.size() > index) {tempStack.push(rollbackStack.top());rollbackStack.pop();}if (!rollbackStack.empty()) {MementoData mementoData = rollbackStack.top();character.restore(mementoData.memento);}while (!tempStack.empty()) {rollbackStack.push(tempStack.top());tempStack.pop();}}void GameStatus() const {std::stack<MementoData> tempStack = undoStack;std::cout << "可回滚状态索引及对应的健康值和等级:\n";while (!tempStack.empty()) {MementoData mementoData = tempStack.top();tempStack.pop();std::cout << "索引:" << mementoData.index \<< " 健康值:" << mementoData.memento.getHealth() \<< " 等级:" << mementoData.memento.getLevel() << std::endl;}}private:struct MementoData {Memento memento;size_t index;};std::stack<MementoData> undoStack;std::stack<MementoData> rollbackStack;
};//demo
void doWorking() {// 创建游戏角色GameCharacter WuKong(100,0);std::cout << "初始状态: ";WuKong.SimulateStatus();// 创建管理者CareTaker BaJie;BaJie.saveMemento(WuKong.save(), 0);// 模拟游戏进展,角色状态发生变化WuKong.setHealth(20);WuKong.setLevel(1);std::cout << "'一难'战斗结束后状态, ";WuKong.SimulateStatus();BaJie.saveMemento(WuKong.save(), 1);WuKong.setHealth(50);WuKong.setLevel(6);std::cout << "'六难'战斗结束后状态, ";WuKong.SimulateStatus();BaJie.saveMemento(WuKong.save(), 2);WuKong.setHealth(90);WuKong.setLevel(9);std::cout << "'九难'战斗结束后状态,";WuKong.SimulateStatus();BaJie.saveMemento(WuKong.save(), 3);WuKong.setHealth(100);WuKong.setLevel(50);std::cout << "'五十难'战斗结束后状态, ";WuKong.SimulateStatus();BaJie.saveMemento(WuKong.save(), 4);WuKong.setHealth(1);WuKong.setLevel(80);std::cout << "'八十难'战斗结束后状态, ";WuKong.SimulateStatus();BaJie.saveMemento(WuKong.save(), 5);WuKong.setHealth(0);WuKong.setLevel(81);std::cout << "'八十一难'战斗失败状态, ";WuKong.SimulateStatus();BaJie.saveMemento(WuKong.save(), 6);//模拟游戏闯关失败if (! WuKong.SimulateStatus()) {std::string select;std::cout << "\n闯关失败!\n请选择回到上一个关卡(undo)?重新开始玩游戏(rollback): ";std::cin >> select;if (select == "undo") {	 // 模拟战斗失败后撤销到上一次状态BaJie.undo(WuKong);std::cout << "恢复至上一次状态: ";WuKong.SimulateStatus();}else if (select == "rollback") {//模拟回滚到指定状态BaJie.GameStatus();size_t index;std::cout << "\n请输入回滚到的状态(从0开始): ";std::cin >> index;std::cout << "恢复至第" << index << "次的状态: ";BaJie.rollback(WuKong, index+1);WuKong.SimulateStatus();}else {std::cout << "游戏结束,欢迎再次体验。" << std::endl;}}return;
}int main() {doWorking();return 0;
}

运行效果

三、备忘录模式应用场景

1. 文本编辑器

在文本编辑器中,用户可能会进行多次编辑操作。备忘录模式可以用来保存每次编辑前的文档状态,以便在用户选择“撤销”操作时恢复到之前的状态。这可以包括:

  • 文字的插入、删除或格式修改。
  • 撤销和重做功能。

2. 游戏开发

在游戏中,角色的状态(如生命值、等级、装备等)需要频繁保存和恢复。例如:

  • 玩家在不同关卡的进度。
  • 角色在战斗中的状态变化,允许玩家在战斗失败后返回上一个状态。

3. 事务管理

在事务处理系统中,可以使用备忘录模式来保存事务的状态,以便在事务失败时能够回滚到之前的状态。这在数据库管理和金融系统中特别重要。

4. 图形编辑器

在图形编辑软件中,用户的每个操作(如移动、缩放、旋转对象)都可能需要被保存,以便用户可以轻松地撤销或重做这些操作。备忘录模式可以管理这些状态,支持:

  • 对图形对象的多级撤销和重做。
  • 保存不同图形状态的快照。

5. 程序设置

在应用程序中,用户可能会更改多个设置(如主题、布局等)。备忘录模式可以在每次更改时保存设置的快照,以便用户在需要时恢复到之前的设置。

6. IDE(集成开发环境)

在代码编辑器或IDE中,备忘录模式可以用于管理代码的不同版本。用户可以在编写代码时保存每个重要的版本,以便在出现问题时恢复到某个特定的代码状态。

7. Web 应用中的表单

在Web应用中,用户填写表单时,可能希望在离开页面后返回并继续填写。备忘录模式可以用来保存表单的当前状态,以便用户可以在返回时恢复之前的输入。

8. 聊天应用

在聊天应用中,用户可能希望撤销发送的消息或恢复删除的消息。备忘录模式可以保存每条消息的状态,以支持撤销功能。

四、总结

备忘录设计模式能够在不暴露对象内部结构的情况下保存和恢复其状态 (不破坏类的封装性)。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • qml tabbar tabbutton toolbar toolbutton 的区别
  • Error: Can not import paddle core while this file exists
  • 【STM32单片机_(HAL库)】3-4-1【中断EXTI】【智能排队控制系统】LCD1602显示字符串
  • 25考研计算机组成原理复习·4.3程序的机器级代码表示
  • Pytorch构建网络模型结构都有哪些方式
  • 通过C# 读取PDF页面大小、方向、旋转角度
  • 攀高行为检测识别摄像机
  • JavaWeb系列四: DOM 上
  • 多线程篇(基本认识 - 线程相关API)(持续更新迭代)
  • 数学建模笔记(四):熵权
  • 排序算法-堆排序
  • 甲方(北汽)渗透测试面试经验分享
  • Nginx: 负载均衡场景下上游服务器异常时的容错机制
  • github访问加速项目@一键部署自动更改host修改加速Github访问
  • k8s调度器Scheduler
  • [笔记] php常见简单功能及函数
  • 345-反转字符串中的元音字母
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • Invalidate和postInvalidate的区别
  • javascript从右向左截取指定位数字符的3种方法
  • js正则,这点儿就够用了
  • Sass 快速入门教程
  • 阿里云应用高可用服务公测发布
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 关于使用markdown的方法(引自CSDN教程)
  • 今年的LC3大会没了?
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端设计模式
  • 全栈开发——Linux
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 深度学习在携程攻略社区的应用
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 微信小程序设置上一页数据
  • MPAndroidChart 教程:Y轴 YAxis
  • scrapy中间件源码分析及常用中间件大全
  • 选择阿里云数据库HBase版十大理由
  • #define与typedef区别
  • (~_~)
  • (04)odoo视图操作
  • (06)金属布线——为半导体注入生命的连接
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (zt)最盛行的警世狂言(爆笑)
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (七)理解angular中的module和injector,即依赖注入
  • (十)c52学习之旅-定时器实验
  • (一)springboot2.7.6集成activit5.23.0之集成引擎
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)c++ std::pair 与 std::make
  • (转)为C# Windows服务添加安装程序
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET4.0并行计算技术基础(1)