备忘录模式-撤销功能的实现

 在idea写代码的过程中,会经常用到一个快捷键——“crtl + z”,即撤销功能。“备忘录模式”则为撤销功能提供了一个设计方案。

1 备忘录模式

备忘录模式提供一种状态恢复机制。在不破坏封装的前提下,捕获对象内部状态并在该对象之外保存这个状态。可以在以后将对象恢复到原先保存的状态。

图 备忘录UML

Originator:原发器,一个需要保存内部状态的普通类,可以创建一个备忘录,也可通过备忘录来恢复其在某个时候的状态。

Memento:备忘录,存储原发器的内部状态。除了原发器本身及管理者类外,备忘录不能直接供其他类使用。

CareTaker:管理者,负责保存备忘录,但不能对备忘录内容进行操作或检查,无须知道备忘录的细节。

@Data
public class IdeaCodeOriginator {private String code;private Integer position;public IdeaCodeOriginator(String code, Integer position) {this.code = code;this.position = position;}public void restoreMemento(IdeaCodeMemento memento) {this.code = memento.getCode();this.position = memento.getPosition();}public IdeaCodeMemento createMemento() {return new IdeaCodeMemento(code,position);}}@Data
public class IdeaCodeMemento {private String code;private Integer position;public IdeaCodeMemento(String code, Integer position) {this.code = code;this.position = position;}
}public class CareTaker {private final Stack<IdeaCodeMemento> mementoStack = new Stack<>();public IdeaCodeMemento getMemento(int num) {IdeaCodeMemento memento = null;while (num-- > 0 && !mementoStack.isEmpty()) {memento = mementoStack.pop();}return mementoStack.isEmpty() ? memento : mementoStack.pop();}public void saveMemento(IdeaCodeMemento memento) {mementoStack.push(memento);}}public class IdeaCodeEditor {public static void main(String[] args) {CareTaker careTaker = new CareTaker();IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);careTaker.saveMemento(originator1.createMemento());IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);careTaker.saveMemento(originator2.createMemento());IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);careTaker.saveMemento(originator3.createMemento());IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);careTaker.saveMemento(originator4.createMemento());//撤回到2步前originator4.restoreMemento(careTaker.getMemento(2));System.out.println(originator4); // IdeaCodeOriginator(code=word, position=2)}}

1.1 优化

1)要避免其他类操作或者检查备忘录的内容。

2)备忘录管理者应该具有通用性。

public interface Memento {
}@Data
public class IdeaCodeOriginator {private String code;private Integer position;public IdeaCodeOriginator(String code, Integer position) {this.code = code;this.position = position;}@Dataprivate static class InnerMemento implements Memento {private String code;private Integer position;public InnerMemento(String code, Integer position) {this.code = code;this.position = position;}}public Memento createMemento() {return new InnerMemento(code,position);}public void restoreMemento(Memento memento) throws Exception {if (memento instanceof InnerMemento) {InnerMemento innerMemento = (InnerMemento) memento;this.code = innerMemento.getCode();this.position = innerMemento.position;} else {throw new Exception("类型错误");}}}public class CareTaker<T> {Stack<T> stack = new Stack<>();public T getMemento(int num) {T memento = null;while (num-- > 0 && !stack.isEmpty()) {memento = stack.pop();}return stack.isEmpty() ? memento : stack.pop();}public void saveMemento(T memento) {stack.push(memento);}}public class IdeaCodeEditor2 {public static void main(String[] args) throws Exception {CareTaker<Memento> objectCareTaker = new CareTaker<>();IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);objectCareTaker.saveMemento(originator1.createMemento());IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);objectCareTaker.saveMemento(originator2.createMemento());IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);objectCareTaker.saveMemento(originator3.createMemento());IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);objectCareTaker.saveMemento(originator4.createMemento());originator4.restoreMemento(objectCareTaker.getMemento(3)); // IdeaCodeOriginator(code=hello, position=1)System.out.println(originator4);}}

2 优缺点

如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。

优点:1)它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤;

缺点:1)资源消耗过大。如果要保存的原发器类的成员变量太多,就不可避免地占用大量的储存空间。每保存一次对象状态都需要消耗一定的系统资源。

3 适用场景

1)保存一个对象在某时刻的全部或部分状态,实现撤销操作。

2)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态实现细节暴露给外界对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/166124.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web自动化测试:测试用例断言!

运行测试用例时&#xff0c;需要判断用例是否执行成功&#xff0c;此时需要有一个我们期望的结果来进行验证。这里unittest中&#xff0c;如果一个case执行的过程中报错&#xff0c;或者我们判断结果不符合期望&#xff0c;就会判定此条用例执行失败&#xff0c;判断的条件主要…

【MySQL】数据库——表操作

文章目录 1. 创建表2. 查看表3. 修改表修改表名add ——增加modify——修改drop——删除修改列名称 4. 删除表 1. 创建表 语法&#xff1a; create table 表名字 ( 列名称 列类型 ) charset set 字符集 collate 校验规则 engine 存储引擎 ; charset set字符集 &#xff0c;若…

【C++代码】二叉搜索树的最近公共祖先,二叉搜索树中的插入操作,删除二叉搜索树中的节点--代码随想录

题目&#xff1a;二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&a…

小程序中如何使用自定义组件应用及搭建个人中心布局

一&#xff0c;自定义组件 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。 开发者可以将页面内的功能模块抽象成自定义组件&#xff0c;以便在不同的页面中重复使用&#xff1b;也可以将复杂的…

MSQL系列(四) Mysql实战-索引分析Explain命令详解

Mysql实战-索引分析Explain命令详解 前面我们讲解了索引的存储结构&#xff0c;我们知道了BTree的索引结构&#xff0c;也了解了索引最左侧匹配原则&#xff0c;到底最左侧匹配原则在我们的项目中有什么用&#xff1f;或者说有什么影响&#xff1f;今天我们来实战操作一下&…

Java并发面试题:(七)ThreadLocal原理和内存泄漏

ThreadLocal是什么&#xff1f; ThreadLocal是线程本地存储机制&#xff0c;可以将数据缓存在线程内部。ThreadLocal存储的变量在线程内共享的&#xff0c;在线程间又是隔离的。 ThreadLocal实现原理&#xff1f; ThreadLocal的底层是ThreadLocalMap&#xff0c;每个Thread都…

YOLOv5算法改进(16)— 增加小目标检测层 | 四头检测机制(包括代码+添加步骤+网络结构图)

前言:Hello大家好,我是小哥谈。小目标检测层是指在目标检测任务中用于检测小尺寸目标的特定网络层。由于小目标具有较小的尺寸和低分辨率,它们往往更加难以检测和定位。YOLOv5算法的检测速度与精度较为平衡,但是对于小目标的检测效果不佳,根据一些论文,我们可以通过增加检…

Kafka Tool(Kafka 可视化工具)安装及使用教程

Kafka Tool&#xff08;Kafka 可视化工具&#xff09;安装及使用教程 Kafka Tool 工具下载 下载地址 http://www.kafkatool.com/download.html 下载界面 不同版本的Kafka对应不同版本的工具&#xff0c;个人使用的是2.11&#xff0c;所以下载的是最新的2.0.8版本&#xff…

android 13/14高版本SurfaceFlinger出现VSYNC-app/VSYNC-appSf/VSYNC-sf剖析

问题背景&#xff1a; 了解surfaceflinger的vsync同学都可能知道vsync属于一个节拍器&#xff0c;主要用来控制有节奏的渲染&#xff0c;不至于会产生什么画面撕裂等现象。 一般vsync都有会有2部分&#xff1a; app部分vsync&#xff0c;控制各个app可以有节奏的上帧 surfacef…

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息&#xff1a;1.2 基本信息&#xff1a;1.2.1 软件支持的内容&#xff1a;1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具&#xff0c;主要是…

【Linux升级之路】8_Linux多线程

目录 一、【Linux初阶】多线程1 | 页表的索引作用&#xff0c;线程基础&#xff08;优缺点、异常、用途&#xff09;&#xff0c;线程VS进程&#xff0c;线程控制&#xff0c;C多线程引入二、【Linux初阶】多线程2 | 分离线程&#xff0c;线程库&#xff0c;线程互斥&#xff0…

【iOS】使用单例封装通过AFNetworking实现的网络请求

这里写目录标题 前言单例封装网络请求1. 首先创建一个继承于NSObject的单例类&#xff0c;笔者这里以Manager对单例类进行命名&#xff0c;然后声明并实现单例类的初始化方法2.实现完单例的创建方法后我们即可通过AFNetworking中的GET方法进行网络请求3.在Controller文件中创建…

免费活动】11月4日敏捷武林上海站 | Scrum.org CEO 亲临现场

活动介绍 过去的几年里&#xff0c;外界的风云变幻为我们的生活增添了一些不一样的色彩。在VUCA世界的浪潮里&#xff0c;每一个人都成为自己生活里的冒险家。面对每一次的变化&#xff0c;勇于探索未知&#xff0c;迎接挑战&#xff0c;努力追逐更好的自己。 七月&#xff0…

Mysql基础与高级汇总

SQL语言分类 DDL:定义 DML&#xff1a;操作 DCL:控制(用于定义访问权限和安全级别) DQL:查询 Sql方言 ->sql&#xff1a;结构化查询语言 mysql:limit oracle:rownum sqlserver:top 但是存储过程&#xff1a;每一种数据库软件一样SQL语法要求: SQL语句可以单行或多行书写&…

【三:Mock服务的使用】

目录 1、工具包2、mock的demo1、get请求2、post请求3、带cookies的请求4、带请求头的请求5、请求重定向 1、工具包 1、&#xff1a;服务包的下载 moco-runner-0.11.0-standalone.jar 下载 2、&#xff1a;运行命令java -jar ./moco-runner-0.11.0-standalone.jar http -p 888…

C# Winform编程(6)高级控件

C# Winform编程&#xff08;6&#xff09;高级控件 RadioButton&#xff08;单选框&#xff09;PictureBox&#xff08;图像框&#xff09;TabControl&#xff08;选项卡&#xff09;ProgressBar(进度条)TrackBar(滑动条)ImageList&#xff08;图像列表控件&#xff09;ToolBar…

Python---死循环概念---while True

在编程中一个靠自身控制无法终止的程序称为“死循环”。 在Python中&#xff0c;我们也可以使用while True来模拟死循环&#xff1a; 代码&#xff1a; while True: print(每天进步一点点) 图示 应用&#xff1a; 比如&#xff0c;在测试里面&#xff0c;自动化测试用例…

Confluence 解决PDF导出乱码问题

1.原因 PDF导出乱码是因为由于服务器缺少必要字体 2.解决办法 下载字体文件将字体文件重命名为simhei.ttf Confluence→管理→PDF导出语言支持&#xff0c;导入字体即可

c#中使用Task.WhenAll

&#x1f680;简介 Task.WhenAll用于等待所有提供的Task对象完成执行。这个方法返回一个新的Task&#xff0c;这个Task将在所有提供的Task完成后完成。如果任何一个Task失败&#xff0c;Task.WhenAll返回的Task也将以异常状态完成。这个方法非常适合在你需要并行执行多个操作&…

垃圾邮件(短信)分类算法实现 机器学习 深度学习 计算机竞赛

文章目录 0 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 垃圾邮件(短信)分类算…