设计模式20-备忘录模式

设计模式20-备忘录

  • 动机
  • 定义与结构
    • 定义
    • 结构
  • C++代码推导
  • 优缺点
  • 应用场景
  • 总结
  • 备忘录模式和序列化
      • 备忘录模式
        • 1. **动机**
        • 2. **实现方式**
        • 3. **应用场景**
        • 4. **优点**
        • 5. **缺点**
      • 序列化
        • 1. **动机**
        • 2. **实现方式**
        • 3. **应用场景**
        • 4. **优点**
        • 5. **缺点**
      • 对比总结

动机

  • 在软件构建过程中,某些对象的状态在转换过程中可能由于某种需要这个程序能够回溯到对象之前处于某个点时的状态。使用一些公用接口来让其他对象得到对象的状态,便会暴露对象细节的实现
  • 如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性呢。
  • 在软件开发中,有时需要在不破坏对象封装性的前提下捕获并存储对象的内部状态,以便稍后可以将对象恢复到以前的状态。这种需求通常出现在实现撤销/恢复操作的场景中,例如文本编辑器中的撤销操作。直接暴露对象的内部状态会违反封装原则,而备忘录模式提供了一种解决方案,使得状态恢复操作能够在不破坏封装性的前提下实现。

定义与结构

定义

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

结构

在这里插入图片描述

解释这张图

这张图描绘了一个典型的UML(统一建模语言)结构图,展示了“备忘录模式”(Memento Pattern)的核心组件及其关系。备忘录模式是一种用于捕获和存储一个对象内部状态的方式,以便可以在未来某个时刻将对象恢复到这个状态。这个模式特别适用于需要保存和恢复对象状态的场景,比如撤销操作、事务处理等。

图中包含了三个主要的类:

  1. Originator(原发器):这个类是需要被保存状态的对象。它包含一个CreateMemento()方法,用于创建一个备忘录对象(Memento),这个对象包含了Originator的当前状态。Originator还包含一个SetMemento(Memento m)方法,用于设置Originator的状态为备忘录对象(Memento)中存储的状态。图中对SetMemento方法的描述可能有些误解,因为通常这个方法不会直接从外部传入一个备忘录对象来设置状态,而是由Caretaker或者系统其他部分将之前保存的备忘录对象传递回Originator来恢复状态。

  2. Memento(备忘录):这个类用于存储Originator的内部状态,以保护这些状态不受外部访问。它包含了一个构造函数(尽管图中没有直接标出),该构造函数可能接受来自Originator的当前状态作为参数。Memento还包含GetState()SetState(state)方法(尽管图中SetState方法的参数可能标记有误,通常备忘录模式中的Memento类不需要SetState方法,因为备忘录主要是用来存储状态的)。但在实际实现中,GetState()方法用于返回备忘录中存储的状态,而SetState(如果存在的话)可能并不是Memento类的一部分,而是用于在Originator中恢复状态的过程中的一部分,但这通常是通过将Memento对象传递给Originator的某个恢复状态方法来实现的。

  3. Caretaker(管理者):这个类负责保存备忘录对象,但不检查备忘录对象的内容。在图中,Caretaker类被描述为有一个ReturnNewMemento(state)方法,这实际上可能是一个误解或错误。在标准的备忘录模式中,Caretaker类会维护一个备忘录对象的列表,但不直接创建新的Memento对象。相反,它可能包含一个AddMemento(Memento m)方法来添加新的备忘录对象,以及一个GetMemento(index)或类似的方法来检索之前保存的备忘录对象。图中的ReturnNewMemento(state)可能试图表达Caretaker返回一个新状态的Memento对象给Originator,但这并不是Caretaker类的典型职责;更常见的是,Caretaker简单地存储和检索Memento对象。

图中箭头表示类之间的交互关系。从Originator到Memento的箭头表示Originator创建Memento对象的过程,而从Caretaker到Originator的箭头(尽管图中没有直接画出)表示Caretaker可能将存储的Memento对象传递回Originator以恢复状态。

需要注意的是,图中的某些细节(如ReturnNewMemento(state)方法和SetState0方法的标记)可能与标准的备忘录模式实现不完全一致,可能是为了简化图示或特定实现的表示。

C++代码推导

以下是一个简单的备忘录模式的C++实现示例,模拟一个文本编辑器的撤销功能。

备忘录类:

#include <iostream>
#include <string>// 备忘录类,用于存储Originator的内部状态
class Memento {
private:std::string state;public:Memento(const std::string& state) : state(state) {}std::string getState() const {return state;}
};

发起人类:

class Originator {
private:std::string state;public:void setState(const std::string& state) {this->state = state;std::cout << "State set to: " << state << std::endl;}std::string getState() const {return state;}Memento* createMemento() {return new Memento(state);}void setMemento(Memento* memento) {state = memento->getState();std::cout << "State restored to: " << state << std::endl;}
};

负责人类:

class Caretaker {
private:Memento* memento;public:void saveMemento(Memento* memento) {this->memento = memento;}Memento* getMemento() {return memento;}~Caretaker() {delete memento;}
};

客户端代码:

int main() {Originator* originator = new Originator();Caretaker* caretaker = new Caretaker();originator->setState("State1");caretaker->saveMemento(originator->createMemento());originator->setState("State2");caretaker->saveMemento(originator->createMemento());originator->setState("State3");// 恢复到上一个状态originator->setMemento(caretaker->getMemento());delete originator;delete caretaker;return 0;
}

运行结果:

State set to: State1
State set to: State2
State set to: State3
State restored to: State2

优缺点

优点:

  1. 封装性:备忘录模式可以在不破坏对象封装性的前提下保存和恢复对象的状态,符合对象的封装原则。
  2. 简化撤销操作:备忘录模式简化了复杂系统中的撤销操作实现,使得对象能够恢复到先前的状态。

缺点:

  1. 内存开销:如果对象的状态较大且备忘录创建频繁,可能会占用大量内存,增加系统开销。
  2. 管理复杂性:备忘录需要被妥善管理,尤其是在需要多个备忘录进行多步撤销时,备忘录的管理和恢复可能会变得复杂。

应用场景

备忘录模式在以下场景中应用较多:

  1. 需要保存对象状态以便恢复:例如实现多步撤销/恢复功能的场景,如文本编辑器、图形编辑器等。
  2. 需要避免暴露对象内部状态:当需要避免外部直接访问对象的内部状态时,可以使用备忘录模式来实现状态保存和恢复。
  3. 对象状态变化复杂且不可预测:在对象状态变化频繁且不可预测的情况下,备忘录模式可以有效管理这些状态变化。

总结

  • 备忘录模式是一种强大的设计模式,通过封装对象的内部状态,实现了状态的保存和恢复功能。虽然它能够有效地支持撤销和恢复操作,但在实际应用中需要注意内存消耗和管理复杂性,特别是在对象状态复杂且变化频繁的场景下。
  • 备忘录模式存储原发器对象的内部状态。在需要时恢复原发器状态。
  • 备忘录模式的核心是信息隐藏,即原发器需要向外界隐藏信息保持其封装性,但同时又需要将再保存到外界。
  • 由于现代语言运行时如JAVA ,c#,都具有相当的对象序列化支持。因此往往采用效率较高,又较容易正确实现的序列化方案来实现备忘录模式。

备忘录模式和序列化

备忘录模式和序列化在某些方面具有相似的功能,但它们的目标和应用场景不同。

备忘录模式

1. 动机

备忘录模式的主要动机是保存和恢复对象的内部状态,而不破坏对象的封装性。它常用于实现撤销/恢复操作,让对象能够恢复到之前的某个状态。

2. 实现方式

备忘录模式通过创建一个“备忘录”对象,将发起人(Originator)对象的内部状态存储在该备忘录对象中。发起人可以使用这个备忘录对象来恢复其内部状态。备忘录模式通常包括三个角色:发起人、备忘录和负责人(Caretaker),其中负责人仅负责管理备忘录的保存和恢复,不直接访问备忘录的内容。

3. 应用场景
  • 撤销/恢复操作:如文本编辑器、图形编辑器中的撤销功能。
  • 历史记录管理:需要保存对象的状态以便以后恢复。
  • 避免对象内部状态暴露:需要保存和恢复对象状态时,但不希望暴露对象的内部实现。
4. 优点
  • 封装性:备忘录模式可以在不破坏对象封装性的前提下保存和恢复状态。
  • 简单性:对外界来说,状态的保存和恢复过程是透明的,简化了撤销/恢复功能的实现。
5. 缺点
  • 内存消耗:如果对象的状态较大或备忘录频繁创建,可能会导致较大的内存开销。
  • 管理复杂性:当涉及多个状态备忘录时,备忘录的管理可能会变得复杂。

序列化

1. 动机

序列化的主要目的是将对象的状态转换为字节流,以便可以将其存储在文件、数据库或通过网络传输,并在以后将其反序列化为原始对象。

2. 实现方式

序列化将对象的状态转换为字节流,并将其保存到存储介质中。反序列化则是将字节流重新转换为对象。序列化通常依赖于语言或平台提供的内置机制,如Java的Serializable接口或C++的自定义序列化逻辑。

3. 应用场景
  • 持久化存储:将对象状态保存到文件或数据库中,以便以后恢复。
  • 网络传输:在分布式系统中,将对象状态通过网络传输到另一个系统。
  • 跨平台数据交换:不同平台之间的数据交换,需要将对象状态转换为通用的字节流格式。
4. 优点
  • 持久性:序列化使得对象状态可以长期保存,并在需要时恢复。
  • 跨平台:序列化后的数据可以在不同平台或系统之间传输和共享。
5. 缺点
  • 性能开销:序列化和反序列化可能会引入性能开销,特别是在大型对象或频繁操作的情况下。
  • 安全性:序列化数据可能会暴露对象的内部状态,存在安全风险,如果反序列化的对象来自不可信的来源,可能会导致安全漏洞。

对比总结

  1. 用途不同

    • 备忘录模式:主要用于保存和恢复对象的状态,以支持撤销/恢复操作,强调对象的封装性。
    • 序列化:主要用于持久化或跨网络传输对象的状态,强调对象的持久性和可传输性。
  2. 实现方式不同

    • 备忘录模式:通常是在内存中保存对象的状态,并通过备忘录对象管理状态的保存和恢复。
    • 序列化:将对象的状态转换为字节流,存储在外部介质中或通过网络传输。
  3. 封装性

    • 备忘录模式:注重保持对象的封装性,外部系统无法访问对象的内部状态。
    • 序列化:通常会暴露对象的内部状态,可能会引发安全问题。
  4. 应用场景不同

    • 备忘录模式:适用于需要频繁保存和恢复对象状态的场景,如撤销功能。
    • 序列化:适用于对象的持久化存储、网络传输、跨平台数据交换等场景。

备忘录模式更适合在应用程序内部管理对象的状态转换,而序列化更适合在应用程序与外部系统之间交换或持久化数据。两者可以结合使用,例如在分布式系统中,备忘录模式管理对象状态,而序列化用于将状态持久化或传输到其他节点。

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

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

相关文章

云服务器和物理服务器的优缺点对比

云服务器优点在于灵活性强、成本效益高、易于扩展且支持全球化部署&#xff1b;缺点则包括安全性与可控性相对较弱&#xff0c;性能可能受限&#xff0c;以及存在服务中断风险。物理服务器则以其高性能、高稳定性、强安全性和完全可控性著称&#xff0c;但成本较高、扩展性受限…

鸿蒙OS ArkTS 省市县级联选择框,封装组件

背景&#xff1a; 公司现在要开发纯血鸿蒙版本APP&#xff0c;我被抽调过来做点功能。现在要做一个省市县级联选择框&#xff0c;并且要封装为组件&#xff0c;供其他页面模块使用。 效果图&#xff1a; 难点&#xff1a; 1. 现在官方文档上只是查到了TextPicker组件是可以做…

Vue3+setup使用vuemap/vue-amap实现地图相关操作

首先要下载依赖并且引入 npm安装 // 安装核心库 npm install vuemap/vue-amap --save// 安装loca库 npm install vuemap/vue-amap-loca --save// 安装扩展库 npm install vuemap/vue-amap-extra --save cdn <script src"https://cdn.jsdelivr.net/npm/vuemap/vue-a…

软件测试需要具备的基础知识【功能测试】---前端知识(三)

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 为了更好的学习软件测试的相关技能&#xff0c;需要具备一定的基础知识。需要学习的基础知识包括&#xff1a; 1、计算机基础 2、前端知识 3、后端知识 4、软件测试理论 后期分四篇文章进行编写&#xff0c;这是第二篇 …

使用es-hadoop同步hive和es之间数据

&#x1f4bb;近期在华为云连接es时的时候发现不能输入账号密码&#xff0c;后面联系华为工程师了解到&#xff0c;华为云默认是非安全模式&#xff0c;即不需要输入账号密码。 如果对你有所帮助&#xff0c;欢迎点赞收藏关注不迷路哦&#x1f493; 目录 使用es-hadoop同步h…

AI时代,我们还可以做什么?

最近看了本书&#xff0c;书名叫做《拐点&#xff1a;站在 AI 颠覆世界的前夜》&#xff0c;作者是万维钢。 本想着看完后&#xff0c;就能掌握一整套 AI 技巧&#xff0c;结果——竟然学了很多道理。 这本书讨论了以下话题&#xff1a; 我们该怎么理解这个 AI 大时代的哲学&am…

国产数据库备份恢复实现

数据库备份恢复是数据库高可用的基本能力&#xff0c;如何通过备份数据快速高效的恢复业务并且满足不同场景下的恢复需求&#xff0c;是各数据库厂商需要关注的要点。本文将介绍几种国产数据库的备份恢复功能&#xff0c;以加深了解。 1、数据库备份恢复方案 数据库备份是生产…

函数实例讲解(七)

文章目录 清洗数据的函数&#xff08;TRIM、CLEAN&#xff09;1、TRIM2、CLEAN3、CONCATENATE4、TEXTJOIN 函数综合练习COUNTIF Excel函数总结1、判断类2、求和类3、计数类4、求平均5、查找引用类6、求数据极值类7、四舍五入类8、提取类9、日期类10、文本处理类11、随机数12、排…

基于SpringBoot+Vue的校园失物招领系统(带1w+文档)

基于SpringBootVue的校园失物招领系统(带1w文档) 基于SpringBootVue的校园失物招领系统(带1w文档) 本课题研发的校园失物招领系统管理系统&#xff0c;就是提供校园失物招领系统信息处理的解决方案&#xff0c;它可以短时间处理完信息&#xff0c;并且这些信息都有专门的存储设…

MyBatis 基本操作 - 注解版

目录 一&#xff0c;查询 - select 1.1 全列查询 1.2 指定列查询 1.3 赋值问题 方法一&#xff1a;起别名 方法二&#xff1a;结果映射 方法三&#xff1a;添加配置 二&#xff0c;新增 - Insert 2.1 使用对象插入 2.2 获取主键 三&#xff0c;删除 - Delete 四&am…

nestjs 全栈进阶--文件上传

nest new upload -p pnpm pnpm i multer pnpm i -D types/multer 允许跨域 1. 单文件上传 我们去新增一个用于上传的handler Post(upload) UseInterceptors(FileInterceptor(file, {dest: uploads })) uploadFile(UploadedFile() file: Express.Multer.File, Body() body) {…

Git使用错误分析

一.fatal: Pathspec is in submodule 我做了这样的错误操作&#xff0c;在一个仓库下的一个子目录&#xff0c;执行了git init 创建了一个子仓库&#xff0c;然后想删掉这个子仓库&#xff0c;就只删除了该子目录下的.git文件夹&#xff0c;而没有删除缓存&#xff0c;执行如下…

Python | Leetcode Python题解之第328题奇偶链表

题目&#xff1a; 题解&#xff1a; class Solution:def oddEvenList(self, head: ListNode) -> ListNode:if not head:return headevenHead head.nextodd, even head, evenHeadwhile even and even.next:odd.next even.nextodd odd.nexteven.next odd.nexteven even…

UVM(3)TLM通信

基本定义 A的方框称之为PORT&#xff0c;B的圆圈称之为EXPORT 要注意&#xff1a;无论是get还是put操作&#xff0c; 其发起者拥有的都是PORT端口&#xff0c; 而不是EXPORT transport操作&#xff0c; 如 transport操作相当于一次put操作加一次get操作&#xff0c; 数据流先…

Spring统一功能处理:拦截器、响应与异常的统一管理

目录 一.拦截器 二.统一数据返回格式 三.统一异常处理 一.拦截器 拦截器是Spring框架提供的核⼼功能之⼀&#xff0c;主要⽤来拦截⽤⼾的请求&#xff0c;在指定⽅法前后&#xff0c;根据业务需要执⾏预先设定的代码。 也就是说&#xff0c;允许开发⼈员提前预定义⼀些逻辑…

c语言-文件

11 文件 目录 11 文件 一、文件系统 二、文件操作方式 1、基于缓冲区文件操作 2、基于非缓冲区文件操作 三、文件操作的常用函数 1、fopen 2、fclose 3、fputc 4、fgetc 5、rewind 6、fseek 7、fputs 8、fgets 9、fwrite 10、fread 11、fprintf 12、fscanf …

【Redis】数据结构篇

文章目录 键值对数据库是怎么实现的&#xff1f;动态字符串SDSC 语言字符串的缺陷SDS结构设计 整数集合整数集合结构设计整数集合的升级操作 哈希表哈希表结构设计哈希冲突链式哈希Rehash渐进式rehashrehash触发条件 压缩列表压缩列表结构设计连续更新压缩列表的缺陷 quicklist…

【Material-UI】Checkbox组件:Indeterminate状态详解

文章目录 一、什么是Indeterminate状态&#xff1f;二、Indeterminate状态的实现1. 基本用法示例2. 代码解析3. Indeterminate状态的应用场景 三、Indeterminate状态的UI与可访问性1. 无障碍设计2. 用户体验优化 四、Indeterminate状态的最佳实践1. 状态同步2. 优化性能3. 提供…

ubuntu20.04 环境搭建教程

1&#xff1a; Ubuntu 版本说明 我使用版本为 ubuntu20.04 ->镜像文件网上下载最新版本 mirrors.huaweicloud.com/ubuntu-releases/20.04.6/ Ubuntu 其他说明 Ubuntu 安装的位置不建议放到 C 盘(除非你只有一个 C 盘) Ubuntu 需要 120G 的空间 2&#xff1…

vue项目前端实现将table导出成excel功能2

使用插件 xlsx、xlsx-style、file-saver 具体引入见文章&#xff1a;vue项目前端实现将table导出成excel功能1 方法一 exportExcelByData&#xff1a;将数据导出成excel&#xff0c;合并单元格需要另外设置 方法二 exportExcelByDom&#xff1a;将页面dom(el-table)导出成…