设计模式行为型——备忘录模式
目录
什么是备忘录模式
备忘录模式的实现
备忘录模式角色
备忘录模式类图
备忘录模式举例
备忘录模式代码实现
备忘录模式的特点
优点
缺点
使用场景
注意事项
实际应用
什么是备忘录模式
备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式(Token Pattern),属于行为型设计模式。在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,当前很多软件都提供了撤销操作,其中就使用了备忘录模式。
备忘录模式的实现
备忘录模式角色
- 原发器角色(Originator):负责创建一个备忘录,记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。同时原发器还可以根据需要决定Memento存储Originator的那些内部状态。
- 备忘录角色(Memento):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
- 管理者角色(Caretaker):管理者又称为负责人,它负责保存备忘录。在管理者类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象(负责任类只提供备忘录对象的读写接口,不提供备忘录属性的读写接口),也无须知道对象的实现细节。管理者对象可以保存一个备忘录数组,从而实现原发器的多次撤销。其存储这些状态信息,除了原发器外其他对象都是不可以访问的,否则就违反了封装的原则。
所以为了实现备忘录模式的封装,需要对备忘录的访问做些控制:
对原发器:可以访问备忘录里的所有信息。
对管理者:不可以访问备忘录里面的数据,但是他可以保存备忘录并且可以将备忘录传递给其他对象。
其他对象:不可访问也不可以保存,它只负责接收从负责人那里传递过来的备忘录同时恢复原发器的状态。
所以就备忘录模式而言理想的情况就是只允许生成该备忘录的那个原发器访问备忘录的内部状态。
备忘录模式类图
备忘录模式举例
要开发一个简单的草稿箱功能,假设只保留文档标题和正文,那么文档标题和正文就属于原发器角色,还需要创建一个文章备忘录,和一个草稿箱作为管理者角色,保存历史文章信息。
文章备忘录 包含了要被恢复的对象的状态。编辑器 创建并在 文章备忘录 对象中存储状态。草稿箱 对象负责从 文章备忘录 中恢复对象的状态。
备忘录模式代码实现
原发器角色
package com.common.demo.pattern.memento;/*** @author Evan Walker 昂焱数据: https://www.ayshuju.com* @version 1.0* @desc 原发器角色 - 编辑器* @date 2023/08/05 10:26:52*/
public class Editor {private String title;private String content;public Editor() {}public Editor(String title, String content) {this.title = title;this.content = content;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public ArticleMemento saveToMemento(){ArticleMemento articleMemento = new ArticleMemento(this.title, this.content);return articleMemento;}public void undoFromMemento(ArticleMemento articleMemento){this.title = articleMemento.getTitle();this.content = articleMemento.getContent();}@Overridepublic String toString() {return "Editor{" +"title='" + title + '\'' +", content='" + content + '\'' +'}';}
}
备忘录角色
package com.common.demo.pattern.memento;/*** @author Evan Walker 昂焱数据: https://www.ayshuju.com* @version 1.0* @desc 备忘录角色 - 文章* @date 2023/08/05 10:28:21*/
public class ArticleMemento {// 标题private String title;// 正文private String content;public ArticleMemento() {}public ArticleMemento(String title, String content) {this.title = title;this.content = content;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}
}
管理者角色
package com.common.demo.pattern.memento;import java.util.Stack;/*** @author Evan Walker 昂焱数据: https://www.ayshuju.com* @version 1.0* @desc 管理员角色 - 草稿箱* @date 2023/08/05 10:30:41*/
public class DraftsBox {// 存储 - 后进先出private final Stack<ArticleMemento> STACK = new Stack<>();public ArticleMemento getMemento() {ArticleMemento articleMemento = STACK.pop();return articleMemento;}public void addMemento(ArticleMemento articleMemento) {STACK.push(articleMemento);}
}
测试类
package com.common.demo.pattern.memento;/*** @author Evan Walker 昂焱数据: https://www.ayshuju.com* @version 1.0* @desc 测试类* @date 2023/08/05 10:31:12*/
public class Test {public static void main(String[] args) {DraftsBox draftsBox = new DraftsBox();Editor editor = new Editor("初始化", "首次发表");ArticleMemento articleMemento = editor.saveToMemento();draftsBox.addMemento(articleMemento);System.out.println("--------第一次编辑,保存草稿之后,信息如下:---------");System.out.println(editor);editor.setTitle("第一次修改");editor.setContent("首次发表后,第一次修改");ArticleMemento articleMemento1 = editor.saveToMemento();draftsBox.addMemento(articleMemento1);System.out.println("--------第一次修改,保存草稿之后,信息如下:---------");System.out.println(editor);editor.setTitle("第二次修改");editor.setContent("首次发表后,第二次修改");System.out.println("--------第一次修改,还没保存草稿,信息如下:---------");System.out.println(editor);System.out.println("-------撤销操作---------");ArticleMemento memento = draftsBox.getMemento();editor.undoFromMemento(memento);System.out.println("--------第一次撤销,之后,信息如下:---------");System.out.println(editor);ArticleMemento memento2 = draftsBox.getMemento();editor.undoFromMemento(memento2);System.out.println("--------第二次撤销,之后,信息如下:---------");System.out.println(editor);}}
测试截图

备忘录模式的特点
优点
- 提供了对象状态的存储与恢复机制:备忘录模式可以将对象的内部状态保存在备忘录中,当需要时能够比较方便地将数据恢复到某个历史的状态。
- 实现了内部状态的封装:除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 支持多次撤销和恢复操作:备忘录模式可以保存多个状态快照,使得客户端可以根据需求选择恢复到某个特定的状态。
缺点
- 资源消耗大:如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
- 对象状态的存储和恢复需要时间和计算资源:备忘录模式需要对对象状态进行序列化和反序列化操作,可能需要消耗一定的时间和计算资源。
使用场景
- 需要在不破坏对象封装性的前提下保存和恢复对象的状态。
- 需要实现多级撤销和恢复操作。
- 需要保存对象历史状态以供分析和审计。
注意事项
- 注意备忘录对象的生命周期管理,避免资源泄露和内存溢出。
- 确保备忘录对象只被相关的原发器对象访问,避免违反封装原则。
- 为了节约内存,可使用原型模式+备忘录模式。
实际应用
- 文本编辑器:可以使用备忘录模式来实现文本编辑器的撤销和恢复功能,将文本的不同版本保存在备忘录中。
- 游戏进度保存与加载:游戏中可以使用备忘录模式来保存和加载游戏的进度,使得玩家可以随时恢复到之前的某个状态。
- 软件撤销和恢复功能:一些软件工具或者编辑器可以使用备忘录模式来实现撤销和恢复功能,保存用户对文件的修改历史。
更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)
相关文章:
设计模式行为型——备忘录模式
目录 什么是备忘录模式 备忘录模式的实现 备忘录模式角色 备忘录模式类图 备忘录模式举例 备忘录模式代码实现 备忘录模式的特点 优点 缺点 使用场景 注意事项 实际应用 什么是备忘录模式 备忘录模式(Memento Pattern)又叫做快照模式&#x…...
Parquet存储的数据模型以及文件格式
文章目录 数据模型Parquet 的原子类型Parquet 的逻辑类型嵌套编码 Parquet文件格式 本文主要参考文献:Tom White. Hadoop权威指南. 第4版. 清华大学出版社, 2017.pages 363. Aapche Parquet是一种能有效存储嵌套数据的列式存储格式,在Spark中应用较多。 …...
Go和Java实现访问者模式
Go和Java实现访问者模式 我们下面通过一个解压和压缩各种类型的文件的案例来说明访问者模式的使用。 1、访问者模式 在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随 着访问者改变而…...
想要通过软件测试的面试,都需要学习哪些知识
很多人认为,软件测试是一个简单的职位,职业生涯走向也不会太好,但是随着时间的推移,软件测试行业的变化,人们开始对软件测试行业的认知有了新的高度,越来越多的人开始关注这个行业,开始重视这个…...
MySQL的索引使用的数据结构,事务知识
一、索引的数据结构🌸 索引的数据结构(非常重要) mysql的索引的数据结构,并非定式!!!取决于MySQL使用哪个存储引擎 数据库这块组织数据使用的数据结构是在硬盘上的。我们平时写的代码是存在内存…...
普及100Hz高刷+1ms响应 微星发布27寸显示器:仅售799元
不论办公还是游戏,高刷及低响应时间都很重要,微星现在推出了一款27寸显示器PRO MP273A, 售价只有799元,但支持100Hz高刷、1ms响应时间,还有FreeSync技术减少撕裂。 PRO MP273A的100Hz高刷新率是其最大的卖点之一&#…...
Java课题笔记~6个重要注解参数含义
1、[掌握]Before 前置通知-方法有 JoinPoint 参数 在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参数。 该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。 不光前置通知的方…...
Windows Docker Desk环境时区问题导致的时间问题解决?
大多docker镜像为了保持镜像大小,采用了alpine linux。 但经常由于时区问题导致时间不准确,解决也很简单。 1.查看事件文件 cd /usr/share/zoneinfo 2.复制时区文件 将文件copy到 /etc/localtime 路径下即可(重庆时区,上海也…...
SpringBoot复习:(22)ConfigurationProperties和@PropertySource配合使用及JSR303校验
一、配置类 package cn.edu.tju.config;import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component;Component ConfigurationPropertie…...
Spring IoC (控制反转)
IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则。 Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。…...
安卓下模拟渲染EGLImageKHR
创建AHardwareBuffer并填充颜色 AHardwareBuffer_Desc desc = {static_cast<uint32_t>(screenW),static_cast<uint32_t>(screenH),...
Spring MVC 框架学习总结
文章目录 初步认识 Spring MVC 框架 一、初识 Spring MVC 框架 二、 三、 四、 五、 六、 七、 八、 九、...
2、简单上手+el挂载点+v-xx(v-text、v-html、v-on、v-show、v-if、v-bind、v-for)
官网: vue3:https://cn.vuejs.org/ vue2:https://v2.cn.vuejs.org/v2/guide/ 简单上手: 流程: 导入开发版本的Vue.js <!--开发环境版本,包含了有帮助的命令行警告--> <script src"https…...
C++初阶语法——命名空间
前言:C,即cplusplus,顾名思义,是C语言promax版本,C兼容C语言。 C的诞生是因为贝尔实验室的本贾尼等大佬认为C语言的语法坑实在太多,拥有许多不足之处(比如命名冲突,)&…...
Axwing.878 线性同余方程
题目 给定n组数据ai, bi , mi,对于每组数求出一个xi,使其满足ai * xibi (mod mi),如果无解则输出impossible。 输入格式 第一行包含整数n。 接下来n行,每行包含一组数据ai , bi , mi。 输出格式 输出共n行,每组数…...
【Pytorch+torchvision】MNIST手写数字识别
深度学习入门项目,含代码详细解析 在本文中,我们将在PyTorch中构建一个简单的卷积神经网络,并使用MNIST数据集训练它识别手写数字。 MNIST包含70,000张手写数字图像: 60,000张用于培训,10,000张用于测试。图像是灰度(即…...
spring boot 集成rocketmq
集成Spring Boot和RocketMQ 在现代的微服务架构中,消息队列已经成为一种常见的异步处理模式,它能解决服务间的同步调用、耦合度高、流量高峰等问题。RocketMQ是阿里巴巴开源的一款消息中间件,性能优秀,功能齐全,被广泛…...
redis Hash类型命令
Redis中的Hash类型有多个常用命令可用于对Hash键进行操作。以下是一些常见的Redis Hash类型命令: HSET:设置Hash字段的值。 它将指定字段与相应的值关联起来,如果字段已经存在,则更新其值,如果字段不存在,…...
P1194 买礼物(最小生成树)(内附封面)
买礼物 题目描述 又到了一年一度的明明生日了,明明想要买 B B B 样东西,巧的是,这 B B B 样东西价格都是 A A A 元。 但是,商店老板说最近有促销活动,也就是: 如果你买了第 I I I 样东西࿰…...
oracle基础语法和备份恢复
Oracle总结 sql命令分类 1.DDL,数据定义语言,create创建/drop销毁 2.DCL,数据库控制语言,grant授权/revoke撤销 3.DML,数据操纵语言,insert/update/delete等sql语句 4.DQL,数据查询语言&am…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
