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概念理解...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
