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概念理解...

vue中引入sass、scss
常规步骤 1. 创建项目 使用vue cli 脚手架工具创建项目 vue create xxxx2. 创建全局样式文件 全局样式变量 路径:/assets/styles/variables.scss //flex 布局变量 $--flex-direction: ("row", "column"); $--flex-position: ("start"…...

Java学习笔记(八)——Lambda表达式
文章目录 Lambda表达式Lambda表达式的省略写法Lambda练习练习1练习2 算法题算法题1 斐波那契数列算法题2 猴子吃桃子算法题3 爬楼梯 Lambda表达式 Lambda表达式是JDK8开始的一种新语法形式。 基本作用:简化函数式接口的匿名内部类的写法。 注意: Lam…...

【JavaEE】CAS
作者主页:paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造&…...

Linux 系统之部署 h5ai 目录列表程序
一、h5ai 介绍 1.1)h5ai 简介 h5ai 是用于 HTTP Web 服务器的现代文件索引器,专注于您的文件。目录以吸引人的方式显示,浏览它们通过不同的视图、面包屑和树概述得到增强。最初 h5ai 是 HTML5 Apache Index 的首字母缩写,但现在它…...

MySQL自增ID耗尽探究:分析与解决方案
MySQL自增ID耗尽探究:分析与解决方案 一、引言 在面试过程中,面试官抛出了一个看似简单却又深入的问题:“MySQL的自增ID用完了,怎么办?” 自增ID耗尽可能看似遥远,但在处理大量数据的系统中,…...

操作系统-操作系统引导(磁盘 操作系统引导过程)
文章目录 总览一个刚买来的磁盘(硬盘)往磁盘安装操作系统后操作系统引导过程例:windows操作系统的初始化程序 总览 一个刚买来的磁盘(硬盘) 此时空空如也 往磁盘安装操作系统后 操作系统在C盘 主引导记录不属于某…...

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖微信小程序端(十三)
地址簿相关功能 1.1 需求分析和设计1.1.1 产品原型1.1.2 接口设计1.1.3 表设计 1.2 代码实现1.2.1 Mapper层1.2.2 Service层1.2.3 Controller层 1.1 需求分析和设计 1.1.1 产品原型 地址簿,指的是消费者用户的地址信息,用户登录成功后可以维护自己的地…...

SAP S/4HANA 2023 Fully-Activated Appliance 虚拟机版介绍
注:市面上所有在售虚拟机均为拷贝本人所作的虚拟机,存在各种技术问题,请知悉。 SAP S4HANA 2023 FAA版本内置了四个Client: 1、000:SAP初始Client,原则上不能动; 2、100:只激活了US…...

【Docker篇】详细讲解容器相关命令
🎊专栏【Docker】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 🎄欢迎并且感谢大家指出小吉的问题🥰 文章目录 🛸容器🌹相关命令🍔案例⭐创建并运…...

LSTM学习笔记
上一篇文章中我们提到,CRNN模型中用于预测特征序列上下文的模块为双向LSTM模块,本篇中就来针对该模块的结构和实现做一些理解。 Bidirectional LSTM模块结构如下图所示: 在Pytorch中,已经集成了LSTM模块,定义如下&…...