当前位置: 首页 > news >正文

设计模式行为型——备忘录模式

目录

什么是备忘录模式

备忘录模式的实现

备忘录模式角色

备忘录模式类图

备忘录模式举例

备忘录模式代码实现

备忘录模式的特点

优点

缺点

使用场景

注意事项

实际应用


什么是备忘录模式

        备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式(Token Pattern),属于行为型设计模式。在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

        备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,当前很多软件都提供了撤销操作,其中就使用了备忘录模式。

备忘录模式的实现

备忘录模式角色

  1. 原发器角色(Originator):负责创建一个备忘录,记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。同时原发器还可以根据需要决定Memento存储Originator的那些内部状态。
  2. 备忘录角色(Memento):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
  3. 管理者角色(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);}}

测试截图 

备忘录模式的特点

优点

  1. 提供了对象状态的存储与恢复机制:备忘录模式可以将对象的内部状态保存在备忘录中,当需要时能够比较方便地将数据恢复到某个历史的状态。
  2. 实现了内部状态的封装:除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
  3. 支持多次撤销和恢复操作:备忘录模式可以保存多个状态快照,使得客户端可以根据需求选择恢复到某个特定的状态。

缺点

  1. 资源消耗大:如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
  2. 对象状态的存储和恢复需要时间和计算资源:备忘录模式需要对对象状态进行序列化和反序列化操作,可能需要消耗一定的时间和计算资源。

使用场景

  1. 需要在不破坏对象封装性的前提下保存和恢复对象的状态。
  2. 需要实现多级撤销和恢复操作。
  3. 需要保存对象历史状态以供分析和审计。

注意事项

  1. 注意备忘录对象的生命周期管理,避免资源泄露和内存溢出。
  2. 确保备忘录对象只被相关的原发器对象访问,避免违反封装原则。
  3. 为了节约内存,可使用原型模式+备忘录模式。

实际应用

  1. 文本编辑器:可以使用备忘录模式来实现文本编辑器的撤销和恢复功能,将文本的不同版本保存在备忘录中。
  2. 游戏进度保存与加载:游戏中可以使用备忘录模式来保存和加载游戏的进度,使得玩家可以随时恢复到之前的某个状态。
  3. 软件撤销和恢复功能:一些软件工具或者编辑器可以使用备忘录模式来实现撤销和恢复功能,保存用户对文件的修改历史。

更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)

相关文章:

设计模式行为型——备忘录模式

目录 什么是备忘录模式 备忘录模式的实现 备忘录模式角色 备忘录模式类图 备忘录模式举例 备忘录模式代码实现 备忘录模式的特点 优点 缺点 使用场景 注意事项 实际应用 什么是备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;又叫做快照模式&#x…...

Parquet存储的数据模型以及文件格式

文章目录 数据模型Parquet 的原子类型Parquet 的逻辑类型嵌套编码 Parquet文件格式 本文主要参考文献&#xff1a;Tom White. Hadoop权威指南. 第4版. 清华大学出版社, 2017.pages 363. Aapche Parquet是一种能有效存储嵌套数据的列式存储格式&#xff0c;在Spark中应用较多。 …...

Go和Java实现访问者模式

Go和Java实现访问者模式 我们下面通过一个解压和压缩各种类型的文件的案例来说明访问者模式的使用。 1、访问者模式 在访问者模式中&#xff0c;我们使用了一个访问者类&#xff0c;它改变了元素类的执行算法。通过这种方式&#xff0c;元素的执行算法可以随 着访问者改变而…...

想要通过软件测试的面试,都需要学习哪些知识

很多人认为&#xff0c;软件测试是一个简单的职位&#xff0c;职业生涯走向也不会太好&#xff0c;但是随着时间的推移&#xff0c;软件测试行业的变化&#xff0c;人们开始对软件测试行业的认知有了新的高度&#xff0c;越来越多的人开始关注这个行业&#xff0c;开始重视这个…...

MySQL的索引使用的数据结构,事务知识

一、索引的数据结构&#x1f338; 索引的数据结构&#xff08;非常重要&#xff09; mysql的索引的数据结构&#xff0c;并非定式&#xff01;&#xff01;&#xff01;取决于MySQL使用哪个存储引擎 数据库这块组织数据使用的数据结构是在硬盘上的。我们平时写的代码是存在内存…...

普及100Hz高刷+1ms响应 微星发布27寸显示器:仅售799元

不论办公还是游戏&#xff0c;高刷及低响应时间都很重要&#xff0c;微星现在推出了一款27寸显示器PRO MP273A&#xff0c; 售价只有799元&#xff0c;但支持100Hz高刷、1ms响应时间&#xff0c;还有FreeSync技术减少撕裂。 PRO MP273A的100Hz高刷新率是其最大的卖点之一&#…...

Java课题笔记~6个重要注解参数含义

1、[掌握]Before 前置通知-方法有 JoinPoint 参数 在目标方法执行之前执行。被注解为前置通知的方法&#xff0c;可以包含一个 JoinPoint 类型参数。 该类型的对象本身就是切入点表达式。通过该参数&#xff0c;可获取切入点表达式、方法签名、目标对象等。 不光前置通知的方…...

Windows Docker Desk环境时区问题导致的时间问题解决?

大多docker镜像为了保持镜像大小&#xff0c;采用了alpine linux。 但经常由于时区问题导致时间不准确&#xff0c;解决也很简单。 1.查看事件文件 cd /usr/share/zoneinfo 2.复制时区文件 将文件copy到 /etc/localtime 路径下即可&#xff08;重庆时区&#xff0c;上海也…...

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 的简写&#xff0c;译为“控制反转”&#xff0c;它不是一门技术&#xff0c;而是一种设计思想&#xff0c;是一个重要的面向对象编程法则。 Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化&#xff0c;控制对象与对象之间的依赖关系。…...

安卓下模拟渲染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)

官网&#xff1a; vue3&#xff1a;https://cn.vuejs.org/ vue2&#xff1a;https://v2.cn.vuejs.org/v2/guide/ 简单上手&#xff1a; 流程&#xff1a; 导入开发版本的Vue.js <!--开发环境版本&#xff0c;包含了有帮助的命令行警告--> <script src"https…...

C++初阶语法——命名空间

前言&#xff1a;C&#xff0c;即cplusplus&#xff0c;顾名思义&#xff0c;是C语言promax版本&#xff0c;C兼容C语言。 C的诞生是因为贝尔实验室的本贾尼等大佬认为C语言的语法坑实在太多&#xff0c;拥有许多不足之处&#xff08;比如命名冲突&#xff0c;&#xff09;&…...

Axwing.878 线性同余方程

题目 给定n组数据ai, bi , mi&#xff0c;对于每组数求出一个xi&#xff0c;使其满足ai * xibi (mod mi)&#xff0c;如果无解则输出impossible。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含一组数据ai , bi , mi。 输出格式 输出共n行&#xff0c;每组数…...

【Pytorch+torchvision】MNIST手写数字识别

深度学习入门项目&#xff0c;含代码详细解析 在本文中&#xff0c;我们将在PyTorch中构建一个简单的卷积神经网络&#xff0c;并使用MNIST数据集训练它识别手写数字。 MNIST包含70,000张手写数字图像: 60,000张用于培训&#xff0c;10,000张用于测试。图像是灰度&#xff08;即…...

spring boot 集成rocketmq

集成Spring Boot和RocketMQ 在现代的微服务架构中&#xff0c;消息队列已经成为一种常见的异步处理模式&#xff0c;它能解决服务间的同步调用、耦合度高、流量高峰等问题。RocketMQ是阿里巴巴开源的一款消息中间件&#xff0c;性能优秀&#xff0c;功能齐全&#xff0c;被广泛…...

redis Hash类型命令

Redis中的Hash类型有多个常用命令可用于对Hash键进行操作。以下是一些常见的Redis Hash类型命令&#xff1a; HSET&#xff1a;设置Hash字段的值。 它将指定字段与相应的值关联起来&#xff0c;如果字段已经存在&#xff0c;则更新其值&#xff0c;如果字段不存在&#xff0c…...

P1194 买礼物(最小生成树)(内附封面)

买礼物 题目描述 又到了一年一度的明明生日了&#xff0c;明明想要买 B B B 样东西&#xff0c;巧的是&#xff0c;这 B B B 样东西价格都是 A A A 元。 但是&#xff0c;商店老板说最近有促销活动&#xff0c;也就是&#xff1a; 如果你买了第 I I I 样东西&#xff0…...

oracle基础语法和备份恢复

Oracle总结 sql命令分类 1.DDL&#xff0c;数据定义语言&#xff0c;create创建/drop销毁 2.DCL&#xff0c;数据库控制语言&#xff0c;grant授权/revoke撤销 3.DML&#xff0c;数据操纵语言&#xff0c;insert/update/delete等sql语句 4.DQL&#xff0c;数据查询语言&am…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...