「聊设计模式」之备忘录模式(Memento)

news2024/11/18 20:46:29

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


前言

  设计模式是软件设计中经典的解决方案,旨在解决软件开发中常见的问题。备忘录模式(Memento)是其中一种经典的设计模式,它允许在不破坏封装的前提下,保存和恢复对象的内部状态。在本文中,我们将深入了解备忘录模式的实现和应用。

摘要

  备忘录模式是一种行为型设计模式,它能够在不破坏对象封装的情况下,保存和恢复对象的内部状态。在备忘录模式中,我们可以将需要保存的对象状态封装到备忘录对象中,并将备忘录对象存储在一个称为管理者的对象中,以便稍后通过管理者对象恢复状态。

备忘录模式

概念

  备忘录模式是一种行为型设计模式,它允许在不暴露对象实现细节的情况下获取对象状态的全部或部分,并将该状态保存在一个备忘录对象中以便于稍后恢复对象状态。这种模式的核心是备忘录对象,它存储了对象的状态信息,同时提供了对该状态信息的访问和恢复操作。备忘录模式通常用于实现撤销和重做功能,在许多编辑器、文本处理器和图形编辑器等应用程序中都有广泛的应用。

结构

备忘录模式由三个主要组件组成:

  • 发起人(Originator):它是需要备份和恢复状态的对象。它存储它自己的内部状态,并且可以创建和恢复备忘录对象。
  • 备忘录(Memento):它存储了发起人对象的内部状态。尽管备忘录具有发起人的状态信息,但是它无法被除了发起人之外的其他对象访问。
  • 管理者(Caretaker):它负责存储备忘录并提供对备忘录的访问。管理者对象可以存储多个备忘录对象,并可用于恢复先前保存的状态。

如下是备忘录模式的UML类图:

在这里插入图片描述

以下是备忘录模式的实现,我们以一个存储文本编辑器历史记录的例子为例:

//备忘录对象
public class TextEditorMemento {
    private final String text;

    public TextEditorMemento(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}
// 发起人对象
public class TextEditor {
    private String text;

    public TextEditor() {
        this.text = "";
    }

    public void setText(String text) {
        this.text = text;
    }

    public TextEditorMemento createMemento() {
        return new TextEditorMemento(text);
    }

    public void restoreMemento(TextEditorMemento memento) {
        this.text = memento.getText();
    }
}
// 管理者对象
public class TextEditorHistory {
    private List<TextEditorMemento> history = new ArrayList<>();

    public void push(TextEditorMemento memento) {
        history.add(memento);
    }

    public TextEditorMemento pop() {
        return history.remove(history.size() - 1);
    }
}

  在这个例子中,TextEditor 是发起人对象,它负责存储文本编辑器的当前文本,并提供方法 createMemento()restoreMemento(TextEditorMemento memento) 来创建备忘录和恢复备忘录。备忘录对象 TextEditorMemento 存储了文本编辑器的文本内容。管理者对象 TextEditorHistory 负责存储备忘录,并提供操作备忘录的方法 push(TextEditorMemento memento)pop()

以下是备忘录模式的应用场景:

  • 当需要保存和恢复对象的一部分或全部状态时。
  • 当直接访问对象状态会导致封装被破坏时。
  • 当需要保存对象的历史快照或可撤销操作历史记录时。

使用场景

备忘录模式(Memento Pattern)在面向对象设计中被广泛应用,其主要作用是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,从而可以在需要的时候将对象恢复到先前的状态。

下面是一些备忘录模式的应用场景:

  1. 撤销操作:在许多应用程序中,用户执行操作时需要有“撤销”操作。通过备忘录模式,可以在执行操作前将当前对象的状态保存到备忘录中,当需要撤销时,从备忘录中获取之前保存的状态并恢复对象。

  2. 数据库事务回滚:在数据库系统中,事务是一组被视为一个单独工作单元的操作。在执行事务时,如果发生了错误,需要将整个事务回滚到最初的状态。备忘录模式可以用来实现这种回滚,将事务执行前的状态保存到备忘录中,当出现错误时可以从备忘录中恢复原始状态。

  3. 游戏存档:在许多游戏中,玩家需要保存游戏进度,以便在之后的时间里恢复到该点。备忘录模式可以用来保存游戏状态,让玩家在需要时回到先前的状态。

  4. 操作系统恢复:当操作系统出现错误或崩溃时,需要将系统的状态恢复到某个先前的时间点。备忘录模式可以利用系统快照机制,将系统的状态保存到备忘录中,从而实现系统恢复。

总之,备忘录模式在许多应用程序中都有着广泛的应用,其主要作用是在不破坏封装性的前提下,捕获对象的内部状态,以便将来可以恢复对象到先前的状态。

优缺点

优点:

  1. 分离了数据与操作,使得数据可以独立于程序进行存储和操作,从而保证了程序的稳定性和安全性;
  2. 实现了撤销和恢复功能,用户可以回退到之前的版本,避免了操作的不可逆性;
  3. 备忘录模式可以在不破坏封装性的前提下捕获一个对象的内部状态,并在需要时回滚该对象到原始状态,比较灵活。

缺点:

  1. 当需要备份大量的数据时,备忘录模式会占用较大的内存空间;
  2. 实现备忘录模式需要对对象进行额外的存储,增加了程序的复杂度;
  3. 由于备忘录模式需要实时存储和恢复对象的状态,可能会影响程序的性能,特别是大规模数据的处理时。

模式实现

TextEditorMemento

package com.example.javaDesignPattern.memento;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/20 11:21
 */
public class TextEditorMemento {
    private final String text;

    public TextEditorMemento(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}

  TextEditorMemento 是备忘录对象,它存储了文本编辑器的文本内容。它具有一个字符串类型的 text 属性和方法 getText() 用于获取 text 属性的值。

TextEditor

package com.example.javaDesignPattern.memento;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/20 11:22
 */
public class TextEditor {
    private String text;

    public TextEditor() {
        this.text = "";
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public TextEditorMemento createMemento() {
        return new TextEditorMemento(text);
    }

    public void restoreMemento(TextEditorMemento memento) {
        this.text = memento.getText();
    }
}

  TextEditor 是发起人对象,它负责存储文本编辑器的当前文本,并提供方法 createMemento()restoreMemento(TextEditorMemento memento) 来创建备忘录和恢复备忘录。它具有一个字符串类型的 text 属性和方法 setText(String text) 用于设置 text 属性的值。

  • TextEditor(): 构造方法,初始化 text 为 “”。
  • void setText(String text): 设置 text 属性的值。
  • TextEditorMemento createMemento(): 创建备忘录对象并返回,它将 text 属性存储在备忘录中。
  • void restoreMemento(TextEditorMemento memento): 从备忘录中恢复 text 属性的值。

TextEditorHistory

package com.example.javaDesignPattern.memento;

import java.util.ArrayList;
import java.util.List;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/20 11:22
 */
public class TextEditorHistory {
    private List<TextEditorMemento> history = new ArrayList<>();

    public void push(TextEditorMemento memento) {
        history.add(memento);
    }

    public TextEditorMemento pop() {
        return history.remove(history.size() - 1);
    }
}

  TextEditorHistory 是管理者对象,它负责存储备忘录,并提供操作备忘录的方法 push(TextEditorMemento memento)pop()。它具有一个 history 属性,它用于存储备忘录对象列表。

  • void push(TextEditorMemento memento): 将备忘录添加到 history 中。
  • TextEditorMemento pop(): 从 history 中删除并返回最近添加的备忘录。

测试用例

public class MementoPatternTest {

    @Test
    public void testMementoPattern() {
        TextEditor editor = new TextEditor();
        TextEditorHistory history = new TextEditorHistory();

        editor.setText("Hello World!");
        history.push(editor.createMemento());

        editor.setText("Goodbye World!");
        history.push(editor.createMemento());

        editor.restoreMemento(history.pop());
        assertEquals(editor.getText(), "Goodbye World!");

        editor.restoreMemento(history.pop());
        assertEquals(editor.getText(), "Hello World!");
    }
}

执行结果如下所示:

在这里插入图片描述

  在这个测试用例中,我们首先创建了一个文本编辑器对象和一个历史记录对象。接下来,我们设置文本编辑器的文本为 “Hello World!”,创建备忘录,并将备忘录添加到历史记录中。然后我们更新文本编辑器的文本为 “Goodbye World!”,创建备忘录,并将备忘录添加到历史记录中。最后,我们将文本编辑器恢复到先前的状态,并验证其文本是否正确。

小结

  备忘录模式是一种行为型设计模式,它允许在不破坏对象封装的情况下,保存和恢复对象的内部状态。在备忘录模式中,我们可以将需要保存的对象状态封装到备忘录对象中,并将备忘录对象存储在一个称为管理者的对象中,以便稍后通过管理者对象恢复状态。

  备忘录模式的主要组件包括发起人对象、备忘录对象和管理者对象。发起人对象是需要备份和恢复状态的对象,它存储它自己的内部状态,并且可以创建和恢复备忘录对象。备忘录对象存储了发起人对象的内部状态。

附录源码

  如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。

☀️建议/推荐你


  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

📣关于我


我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中科驭数联合处理器芯片全国重点实验室获得FPL 2023最佳论文奖

在2023年的FPGA领域顶级会议FPL (International Conference on Field Programmable Logic and Applications) 上&#xff0c;由中科驭数团队、中国科学院计算技术研究所处理器芯片全国重点实验室团队共同完成的论文《Co-ViSu: a Video Super-Resolution Accelerator Exploiting…

高教杯数学建模竞赛A题文章写作要点与示范

数学建模竞赛写作最重要的一点 LaTeX 很重要 非常重要 非常重要一定要规范 美观 写作注意事项 标准的附录详实的支撑材料和清晰的支撑材料说明 文章中所有的图片都应该包含在支撑材料中正确得引用参考文献模型的评价部分应当包含 模型优点模型缺点改进方案图像绘制应当标准假设…

通过uni.chooseImage返回的临时路径转为base64

uniapp官方API文档&#xff1a;https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage 代码在后面 chooseimage的succes函数中的res.tempFilePaths&#xff0c;是图片的一个临时路径&#xff0c;没法直接传给后端接口使用&#xff0c;且接口需要的是base64格式的 ge…

使用dokcer部署分布式任务调度平台XXL-JOB

XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 部署docker略有需要看下面文档即可 ​​​​​​yum安装docker以及安装指定版本docker_yum安装指定版本dock…

迅为RK3588开发板修改编译工具路径

1 因为此章节以 rknn_yolov5_demo 在 RK3588 Linux 64 位平台上运行为例&#xff0c;所以修改 examples/rknn_yolov5_demo/build-XXX.sh 的编译工具路径&#xff0c;如下图所示&#xff1a; 2 修改 build-linux_RK3588.sh 文件&#xff0c;将 TOOL_CHAIN 修改为 gcc-arm-10.3…

set和map通过一颗红黑树进行封装

T是什么我不知道&#xff0c;但是我知道set 那么T一定得是key &#xff0c; map一定得是pair的数据类型 得用一颗模板是红黑树&#xff0c;实例化出map和set ---------------------------------------------------------------------------------------------------------…

如何与QVC 建立EDI连接?

QVC&#xff0c;全称为Quality, Value, Convenience&#xff08;品质、价值、便利&#xff09;&#xff0c;成立于1986年&#xff0c;是一家全球领先的零售电视和在线零售商。作为一家多渠道零售商&#xff0c;QVC致力于为客户提供高品质、独特的商品&#xff0c;通过电视、互联…

山石网科国产化防火墙,打造全方位边界安全解决方案

互联网的快速发展促进了各行各业的信息化建设&#xff0c;但也随之带来了诸多网络安全风险。大部分组织机构采用统一互联网接入方案&#xff0c;互联网出口承担着内部用户访问互联网的统一出口和对外信息服务的入口&#xff0c;因此在该区域部署相匹配的安全防护手段必不可少。…

Spring WebFlux使用未加前缀的双通配符模式绕过安全性CVE-2023-34034

文章目录 0.前言漏洞漏洞介绍描述 1.参考文档2.基础介绍3.解决方案3.1. 升级版本 4.漏洞修复源码分析5. 漏洞利用示例 0.前言 背景&#xff1a;公司项目扫描到 WebFlux中使用"**"作为模式会导致Spring Security和Spring WebFlux之间 CVE-2023-34034漏洞 漏洞 高 | 2…

junit.Test误踩坑,识别不到@Test注解,无法运行测试方法

问题的出现源自于下面的一段代码&#xff1a; 在这一段代码中&#xff0c;只看到可以运行的main方法&#xff0c;无法看到test方法可以运行的标志。 只能运行main()方法。 开始排查&#xff0c;对junit包的导入进行检查&#xff0c;发现是没有问题的。 怀疑是否是IntelliJ IDE…

lazada跨境电商商品数据采集

Lazada跨境电商商品数据采集可以使用以下两种方法&#xff1a; 手动采集&#xff1a;可以在Lazada网站上手动搜索商品信息&#xff0c;然后复制粘贴到Excel表格中。这种方法比较麻烦&#xff0c;需要逐个搜索和记录商品信息&#xff0c;适合采集数量较少的商品数据。使用采集软…

无涯教程-JavaScript - PI函数

描述 PI函数返回数字3.14159265358979,数学常数pi,精确到15位数字。 语法 PI ()争论 PI函数语法没有参数。 适用性 Excel 2007,Excel 2010,Excel 2013,Excel 2016 Example JavaScript 中的 PI函数 - 无涯教程网无涯教程网提供描述PI函数返回数字3.14159265358979,数学常…

基于Android+OpenCV+CNN+Keras的智能手语数字实时翻译——深度学习算法应用(含Python、ipynb工程源码)+数据集(二)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 数据增强3. 模型构建1&#xff09;定义模型结构2&#xff09;优化损失函数 相关其它博客工程源代码下载其它资料下载 前言 本项目依赖于Keras深度学习模型&#xff0c;旨在对手语进行分类和实时识…

Vue.js入门模板语法[上] 及Vue.js实现购物车---详细讲解

前言 前面我们学习了Vue的基础入门&#xff0c;接下来我们学习有关Vue的模板语法&#xff0c;学习Vue语法能提高我们的前端开发效率 Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML &a…

肖sir__mysql之存储练习题__013

实验 一、 实验要求&#xff1a; 理解存储过程的概念掌握存储过程的语法格式、使用方法掌握存 储过程的创建、执行 二、实验前提&#xff1a; – drop table if exists student; – Create table student – (Id varchar(255), #学号 – Name varchar(255), #姓名 – Roomid…

4、wireshark使用教程

文章目录 一、wireshark简介二、环境三、wireshark抓包三、wireshark过滤器使用 一、wireshark简介 Wireshark是使用最广泛的一款「开源抓包软件」&#xff0c;常用来检测网络问题、攻击溯源、或者分析底层通信机制。 Wireshark抓包原理&#xff1a; 单机情况&#xff1a;电脑…

Java中常见的线程池

一、Java中常见的线程池 1.为什么使用线程池 重用线程池的线程&#xff0c;避免因为线程的创造和销毁所带来的性能开销。有效控制线程池的最大并发数&#xff0c;避免大量的线程之间因抢占系统资源而阻塞。能够对线程进行简单的管理&#xff0c;并提供一些特定的操作&#xf…

PY32F003F18之DMA串口

PY32F003F18使用DMA串口&#xff0c;官方程序省FLASH&#xff0c;但不省内存。单片机内存够大&#xff0c;节省没意义&#xff0c;故做了修改&#xff0c;少用HAL库中的发送和接收&#xff0c;从里面抠出有用的部分&#xff0c;修修改改就可以了。 一、DMA串口初始化流程&…

未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序

1.第一步&#xff1a;下载 Microsoft Access Database Engine Microsoft Access Database Engine 2010 Redistributable Download 2.第二步: 安装下载的引擎软件 3.第三步&#xff1a;重新连接&#xff1b; 代码如下: private void button1_Click(object sender, EventArgs …

【M malloc送书第二期】朋友圈大佬都去读研了,这份备考书单我码住了!

文章目录 01 《**数据结构与算法分析**》02 《计算机网络&#xff1a;自顶向下方法》03 《现代操作系统》04 《深入理解计算机系统》01 《概率论基础教程&#xff08;原书第10版》03 《线性代数及其应用》 八九月的朋友圈刮起了一股晒通知书潮&#xff0c;频频有大佬晒出“研究…