C++ 设计模式之备忘录模式
【声明】本题目来源于卡码网(题目页面 (kamacoder.com))
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】
【设计模式大纲】

【简介】
-- 什么是备忘录模式 (第17种模式)
备忘录模式(Memento Pattern)是⼀种⾏为型设计模式,它允许在不暴露对象实现的情况下捕获对象的内部状态并在对象之外保存这个状态,以便稍后可以将其还原到先前的状态。

【基本结构】
备忘录模式包括以下⼏个重要⻆⾊:
- 发起⼈Originator : 需要还原状态的那个对象,负责创建⼀个【备忘录】,并使⽤备忘录记录当前时刻的内部状态。
- 备忘录Memento : 存储发起⼈对象的内部状态,它可以包含发起⼈的部分或全部状态信息,但是对外部是不可⻅的,只有发起⼈能够访问备忘录对象的状态。
备忘录有两个接⼝,发起⼈能够通过宽接⼝访问数据,管理者只能看到窄接⼝,并将备忘录传递给其他对象。
- 管理者Caretaker : 负责存储备忘录对象,但并不了解其内部结构,管理者可以存储多个备忘录对象。
- 客户端:在需要恢复状态时,客户端可以从管理者那⾥获取备忘录对象,并将其传递给发起⼈进⾏状态的恢复。

【基本实现】
下面以Java代码作以简要说明:
1. 创建发起⼈类:可以创建备忘录对象
class Originator {private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}// 创建备忘录对象public Memento createMemento() {return new Memento(state);}// 通过备忘录对象恢复状态public void restoreFromMemento(Memento memento) {state = memento.getState();}
}
2. 创建备忘录类:保存发起⼈对象的状态
class Memento {private String state;// 保存发起⼈的状态public Memento(String state) {this.state = state;}public String getState() {return state;}
}
3. 创建管理者:维护⼀组备忘录对象
class Caretaker {private List<Memento> mementos = new ArrayList<>();public void addMemento(Memento memento) {mementos.add(memento);}public Memento getMemento(int index) {return mementos.get(index);}
}
4. 客户端使用备忘录模式
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file MementoMode.hpp
* @brief 备忘录模式
* @autor 写代码的小恐龙er
* @date 2024/01/19
*/
public class Main {public static void main(String[] args) {// 创建发起⼈对象Originator originator = new Originator();originator.setState("State 1");// 创建管理者对象Caretaker caretaker = new Caretaker();// 保存当前状态caretaker.addMemento(originator.createMemento());// 修改状态originator.setState("State 2");// 再次保存当前状态caretaker.addMemento(originator.createMemento());// 恢复到先前状态originator.restoreFromMemento(caretaker.getMemento(0));System.out.println("Current State: " + originator.getState());}
}
【使用场景】
备忘录模式在保证了对象内部状态的封装和私有性前提下可以轻松地添加新的备忘录和发起⼈,实现“备份”,不过备份对象往往会消耗较多的内存,资源消耗增加。
备忘录模式常常⽤来实现撤销和重做功能,⽐如在Java Swing GUI编程中,javax.swing.undo 包中的撤销(undo)和重做(redo)机制使⽤了备忘录模式。UndoManager 和UndoableEdit 接⼝是与备忘录模式相关的主要类和接⼝。
【C++编码部分】
1. 题目描述
小明正在设计一个简单的计数器应用,支持增加(Increment)和减少(Decrement)操作,以及撤销(Undo)和重做(Redo)操作,请你使用备忘录模式帮他实现。
2. 输入描述
输入包含若干行,每行包含一个字符串,表示计数器应用的操作,操作包括 "Increment"、 "Decrement"、"Undo" 和 "Redo"。
3. 输出描述
对于每个 "Increment" 和 "Decrement" 操作,输出当前计数器的值,计数器数值从0开始 对于每个 "Undo" 操作,输出撤销后的计数器值。 对于每个 "Redo" 操作,输出重做后的计数器值。
4. C++编码实例
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file MementoMode.hpp
* @brief 备忘录模式
* @autor 写代码的小恐龙er
* @date 2024/01/19
*/#include <iostream>
#include <string>
#include <vector>
#include <stack>using namespace std;// 前置声明// 备忘录类 -- 保存发起⼈对象的状态
class Memento;
// 发起人类 -- 可以创建备忘录对象
class Counter;
// 管理者 -- 一组备忘录对象
class MementoManager;// 类的定义// 备忘录类
class Memento
{
// 成员数据
private:int _value;// 备忘录操作的成员函数
public:Memento(int value){SetValue(value);}void SetValue(int value){this->_value = value;}int GetValue(){return this->_value;}
};// 发起人 类
class Counter
{
// 成员数据
private:int _value;// 发起人的计数值std::stack<Memento *> _undoStack; // 发起人撤销操作的栈 std::stack<Memento *> _redoStack; // 发起人重新操作的栈// 成员函数
public:Counter(){}// 获取值int GetValue(){return this->_value;}// 增加计数值void IncreaseValue(Memento *memento){//清空重做的栈while(!_redoStack.empty()){_redoStack.pop();}_undoStack.push(memento);_value++;}// 减少计数值void DecreaseValue(Memento *memento){//清空重做的栈while(!_redoStack.empty()){_redoStack.pop();}_undoStack.push(memento);_value--;}// 撤销操作void Undo(Memento *memento){if(!_undoStack.empty()){_redoStack.push(memento);_value = _undoStack.top()->GetValue();}}// 重新操作void Redo(Memento *memento){if(!_redoStack.empty()){_undoStack.push(memento);_value = _redoStack.top()->GetValue();}}
};// 管理者
class MementoManager
{
// 成员数据
private:std::vector<Memento *> _mementoVec;// 成员函数
public:// 增加备忘录void AddMemento(Memento *mento){_mementoVec.push_back(mento);}// 寻找备忘录 按照顺序 或者 备忘录中的计数值Memento * GetMemento(int index){if(index >= _mementoVec.size()) return nullptr;else return _mementoVec[index];}
};// 客户端
int main()
{// 操作类型string type = "";// 新建 发起人 类 Counter *counter = new Counter();// 新建备忘录管理者MementoManager *manager = new MementoManager();// 新建备忘录Memento *memento = nullptr;// 等待输入指令while(std::cin >> type){if(type == "Increment"){memento = new Memento(counter->GetValue());counter->IncreaseValue(memento);}else if(type == "Decrement"){memento = new Memento(counter->GetValue());counter->DecreaseValue(memento);}else if(type == "Undo"){memento = new Memento(counter->GetValue());counter->Undo(memento);}else if(type == "Redo"){memento = new Memento(counter->GetValue());counter->Redo(memento);}// 将备忘录添加至管理者中 【此时备忘录管理者可以去做其他的事情】manager->AddMemento(memento);// 输出计数器的值std::cout<< counter->GetValue() << endl;}// 析构if(memento != nullptr){delete memento;memento = nullptr;}delete counter;counter = nullptr;delete manager;manager = nullptr;return 0;
}
......
To be continued.
相关文章:
C++ 设计模式之备忘录模式
【声明】本题目来源于卡码网(题目页面 (kamacoder.com)) 【提示:如果不想看文字介绍,可以直接跳转到C编码部分】 【设计模式大纲】 【简介】 -- 什么是备忘录模式 (第17种模式) 备忘录模式(Meme…...
【项目搭建三】SpringBoot引入redis
添加依赖 本文使用spring data redis访问和操作redis,pom文件中加入以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </depende…...
漫谈广告机制设计 | 听闻RTA要搞二次竞价了?牛啊!
听闻RTA要搞二次竞价了? 读者群里反馈说,某大厂的RTA支持做二次竞价了。笔者听闻后,竖起了大拇指,牛! RTA RTA(Real Time API), 是一种实时的广告程序接口,用于满足广告主实时个性化的投放需…...
第04章_IDEA的安装与使用(下)(IDEA断点调试,IDEA常用插件)
文章目录 第04章_IDEA的安装与使用(下)8. 快捷键的使用8.1 常用快捷键8.2 查看快捷键1、已知快捷键操作名,未知快捷键2、已知快捷键,不知道对应的操作名 8.3 自定义快捷键8.4 使用其它平台快捷键 9. IDEA断点调试(Debug)9.1 为什么…...
HBase鉴权设计以及Kerberos鉴权方法
文章目录 1. HBase鉴权方式整理2. Kerboers鉴权架构整理2.1 kerberos的实现架构2.2 相关核心参数整理 3. 客户端的鉴权设计3.1 安全管控权限3.2 安全管控级别3.3 相关操作3.3.1 用户授权3.3.2 回收权限 4. 疑问和思考6. 参考文章 鉴权,分别由鉴和权组成 鉴…...
【华为GAUSS数据库】IDEA连接GAUSS数据库方法
背景:数据库为华为gauss for opengauss 集中式数据库 IDEA提供了丰富的各类型数据库驱动,但暂未提供Gauss数据库。可以通过以下方法进行连接。 连接后, 可以自动检查xml文件中的sql语句是否准确,表名和字段名是否正确还可以直接在…...
[java基础揉碎]键盘输入语句
介绍 在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。 需要一个扫描器(对象),就是Scanner 用到的scanner代码例子...
Redis 面试题 | 01.精选Redis高频面试题
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
Crow:实现点击下载功能
Crow:设置网站的index.html-CSDN博客 讲述了如何完成一个最简单的网页的路由 很多网页提供了下载功能,怎么实现呢,其实也很简单。 假设网页的目录结构如图 $ tree static static ├── img │ └── goodday.jpg └── index.html //index.html <html> <body&…...
2024年华为OD机试真题-内存冷热标记-Python-OD统一考试(C卷)
题目描述: 现代计算机系统中通常存在多级的存储设备,针对海量workload的优化的一种思路是将热点内存页优先放到快速存储层级,这就需要对内存页进行冷热标记。 一种典型的方案是基于内存页的访问频次进行标记,如果统计窗口内访问次数大于等于设定阈值,则认为是热内存页,否…...
Webpack5入门到原理9:处理字体图标资源
1. 下载字体图标文件 打开阿里巴巴矢量图标库选择想要的图标添加到购物车,统一下载到本地 2. 添加字体图标资源 src/fonts/iconfont.ttfsrc/fonts/iconfont.woffsrc/fonts/iconfont.woff2src/css/iconfont.css/注意字体文件路径需要修改 src/main.js import { …...
【Docker】在Windows操作系统安装Docker前配置环境
欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Docker容器》序列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…...
Webpack5入门到原理21:提升开发体验
SourceMap 为什么 开发时我们运行的代码是经过 webpack 编译后的,例如下面这个样子: /** ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").* This devtool is neither made for product…...
YOLOv8改进 | Conv篇 | 在线重参数化卷积OREPA助力二次创新(提高推理速度 + FPS)
一、本文介绍 本文给大家带来的改进机制是一种重参数化的卷积模块OREPA,这种重参数化模块非常适合用于二次创新,我们可以将其替换网络中的其它卷积模块可以不影响推理速度的同时让模型学习到更多的特征。OREPA是通过在线卷积重参数化(Online Convolutional Re-parameteriza…...
conda国内加速
1、配置国内源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ 2、显示源地址 conda config --set show_channel_urls yes...
RabbitMQ-数据持久化
一、持久化类型 1、交换机持久化(SpringAMQP默认) 2、队列持久化(SpringAMQP默认) 3、消息持久化 二、消息持久化 1、纯内存操作 如果采用纯内存操作,那么消息存储达到队列的上限之后,会有一个page ou…...
JS-WebAPIs-本地存储(五)
• 本地存储介绍 以前我们页面写的数据一刷新页面就没有了,是不是?随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常 性在本地存储大量的数据…...
了解Vue中日历插件Fullcalendar
实现效果如下图: 月视图 周视图 日视图 官方文档地址:Vue Component - Docs | FullCalendar 1、安装与FullCalendar相关的依赖项 npm install --save fullcalendar/vue fullcalendar/core fullcalendar/daygrid fullcalendar/timegrid fullcalend…...
Cloudreve存储策略-通过从机存储来拓展容量
Sham的云服务器是搬瓦工最低低低配的,1H 0.5G不说,硬盘容量也只有10g,说实话,装了宝塔面板和服务器套件后,基本满了,这时又想在云服务器上打个网盘用于下载、存储,这时就需要拓展硬盘࿰…...
java进阶-jvm精讲及实战
深入了解jvm及实战 1.引言2.jvm概念理解 1.引言 jvm是深入了解java底层逻辑的必备知识储备,在中大型开发团队里,中高级工程师必须要了解和掌握,也是中高级工程师面试必考题,在实战中用于程序性能调优,内存泄露分析等 2.jvm概念理解...
AI测试的现状与未来:AI会取代人工测试吗
在软件测试领域,AI技术的崛起正掀起一场深刻变革。从自动化测试用例生成到智能缺陷检测,AI的应用场景不断拓展,效率提升显著。这让众多软件测试从业者不禁心生焦虑:AI是否会彻底取代人工测试?要解答这个问题࿰…...
录音总结会议纪要推荐,零基础新手避坑可直接上手指南
这是专为零基础新手整理的2026年录音转会议纪要避坑指南,适配喜欢尝试效率工具、想借助AI节省整理时间的朋友,所有推荐均按实际场景适配度排序,内容简洁易懂,看完可直接上手,无需自行试错踩坑。很多新手接触录音转会议…...
淘金币全自动脚本终极指南:每天节省20分钟,淘宝任务一键完成
淘金币全自动脚本终极指南:每天节省20分钟,淘宝任务一键完成 【免费下载链接】taojinbi 淘宝淘金币自动执行脚本,包含蚂蚁森林收取能量,芭芭农场全任务,解放你的双手 项目地址: https://gitcode.com/gh_mirrors/ta/t…...
BUUCTF [ZJCTF 2019]NiZhuanSiWei 通关详解:从PHP伪协议到反序列化的三层渗透
1. 题目初探与源码分析 第一次看到这道题的时候,我盯着屏幕上的PHP源码看了足足五分钟。题目给出了一个简单的PHP文件,要求我们通过三个参数来获取flag。这种层层递进的题目设计在CTF中很常见,但每一步都需要仔细思考。 源码的核心逻辑是这样…...
Unity交通仿真入门:从零到一搭建十字路口红绿灯与车辆AI(附完整C#源码)
Unity交通仿真实战:十字路口红绿灯与车辆AI开发指南 在游戏开发和城市模拟领域,交通仿真一直是个充满挑战又极具实用价值的课题。想象一下,你正站在一个繁忙的十字路口,观察着红绿灯有节奏地变换,车辆井然有序地通过—…...
常用工具清单
Mem Reduct — 免费内存优化器 https://mem-reduct.com/#system-requirements Redis — Github 安装地址 Another-Redis-Desktop-Managerhttps://github.com/qishibo/AnotherRedisDesktopManager/tags redishttps://github.com/tporadowski/redis/tags...
LVGL 8.x 实战:搞定Label点击、背景色和文字对齐的3个高频难题
LVGL 8.x实战:攻克Label交互、样式与布局的三大核心痛点 在嵌入式UI开发领域,LVGL以其轻量级和高度可定制性成为众多开发者的首选。但当我们真正开始构建第一个界面时,往往会遇到一些看似简单却令人抓狂的问题——为什么Label不能点击&#…...
【码上爬】 题十一:wasm小试牛刀 wasm文件处理,堆栈分析
暗号:aHR0cHM6Ly9tYXNoYW5ncGEuY29tL3Byb2JsZW0tZGV0YWlsLzExLw题目:先分析数据接口,可以看到m和ts是加密的,但是这里的ts的值应该是一个时间戳,所以主要要逆向的值是m:然后在发起程序的最上面的堆栈下一个…...
5分钟掌握Cherry MX键帽3D建模:打造你的专属机械键盘
5分钟掌握Cherry MX键帽3D建模:打造你的专属机械键盘 【免费下载链接】cherry-mx-keycaps 3D models of Chery MX keycaps 项目地址: https://gitcode.com/gh_mirrors/ch/cherry-mx-keycaps 你是否曾想过亲手设计一套完全属于自己的机械键盘键帽?…...
Newbie-Guideline数据库实战:SQL查询与ER模型设计的完整教程
Newbie-Guideline数据库实战:SQL查询与ER模型设计的完整教程 【免费下载链接】Newbie-Guideline 컴퓨터과학/공학 신입생 및 비전공자 신입을 위한 지침서 项目地址: https://gitcode.com/gh_mirrors/ne/Newbie-Guideline Newbie-Guideline是面向计算机科学/…...
