当前位置: 首页 > 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…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...