设计模式第20讲——备忘录模式(Memento)

news2024/9/28 3:18:37

目录

一、什么是备忘录模式

二、角色组成

三、优缺点

四、应用场景 

五、代码实现

5.0 UML类图

5.1 EditorMemento——备忘录(Memento)

5.2 Editor——源发器(Originator)

5.3 History——管理者(Caretaker)

5.4 testMemento

六、总结


一、什么是备忘录模式

备忘录模式又称快照模式,是一种行为型设计模式。它可以在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态,以便在需要的时候恢复到原先保存的状态

二、角色组成

  • 源发器(Originator):需要保存和恢复状态的对象。它创建一个备忘录对象,用于存储当前对象的状态,也可以使用备忘录对象恢复自身的状态。
  • 备忘录(Memento):存储源发器对象的状态。备忘录对象可以包括一个或多个状态属性,源发器可以根据需要保存和恢复状态。
  • 管理者(Caretaker):负责保存备忘录对象,但不能修改备忘录对象的内容。它可以存储多个备忘录对象,并决定何时将备忘录恢复给源发器。

三、优缺点

优点:

  • 状态保存与恢复:备忘录模式可以帮助我们保存对象的状态,并在需要时恢复到之前的状态。这在某些情况下非常有用,比如撤销操作或者程序崩溃后的恢复。
  • 封装性和隔离性:可以确保对象的状态保存在备忘录对象中,而不会暴露给其他对象。这为对象的封装性和隔离性提供了保护,使得对象的状态变化对其他对象是透明的。

缺点:

  • 内存占用:可能引起较大的内存占用,特别是当对象的状态较多且状态改变频繁时。每个备忘录对象都需要保存一份完整的状态,如果状态较多或者备忘录对象较多,可能会消耗大量内存。
  • 性能开销:备忘录模式涉及到创建、存储和恢复状态的操作,这些操作可能引起一定的性能开销。特别是在状态较大或者对象较复杂的情况下,备忘录模式的性能可能会受到影响。

四、应用场景 

浏览器的回退:当我们点击回退箭头时,浏览器会回退到上一个被浏览的网站,以显示之前访问的页面。

文本编辑器的撤销:如果误删了一些内容或者想恢复之前的修改,可以进行撤销操作。

数据库事务管理:当执行数据库操作时,我们可以将当前数据库的状态保存到备忘录对象中,在回滚操作或者发生错误时,可以使用备忘录对象恢复到之前的数据库状态。

五、代码实现

下面以文本编辑器为例,解释一下备忘录模式。

用户可以在编辑器中输入文本,并允许回退到之前的编辑状态。其中Editor类代表文本编辑器(源发器),它具有保存和恢复文本内容的功能。EditorMemento类表示备忘录对象,用于保存Editor的状态。History类作为管理者,负责保存和管理备忘录对象。

5.0 UML类图

5.1 EditorMemento——备忘录(Memento)

/**
 * @author Created by njy on 2023/7/1
 * 1.备忘录(Memento):备忘录,保存编辑器的状态
 * 定义:存储源发器对象的状态。备忘录对象可以包括一个或多个状态属性,源发器可以根据需要保存和恢复状态。
 */
public class EditorMemento {
    //文本内容 (可以是属性、也可以是对象)
    private  String content;

    public EditorMemento(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}

5.2 Editor——源发器(Originator)

/**
 * @author Created by njy on 2023/7/1
 * 2.源发器(Originator):文本编辑器
 * 定义:需要保存和恢复状态的对象。它创建一个备忘录对象,用于存储当前对象的状态,也可以使用备忘录对象恢复自身的状态。
 */
public class Editor {
    //内容(可以是属性、也可以是对象)
    private String content;

    public void setContent(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    // 创建备忘录对象,保存当前状态
    public EditorMemento createMemento() {
        return new EditorMemento(content);
    }

    // 恢复备忘录对象保存的状态
    public void restoreMemento(EditorMemento memento) {
        content = memento.getContent();
    }

}

5.3 History——管理者(Caretaker)

/**
 * @author Created by njy on 2023/7/2
 * 3.管理者(Caretaker):历史记录
 * 定义:负责保存备忘录对象,但不能修改备忘录对象的内容。它可以存储多个备忘录对象,并决定何时将备忘录恢复给源发器。
 */
public class History {
    //备忘录可以保存多个状态
    private final List<EditorMemento> mementos = new ArrayList<>();

    // 保存备忘录对象的状态
    public void push(EditorMemento memento) {
        mementos.add(memento);
    }

    // 弹出(移除)最近保存的备忘录对象,并返回它
    public EditorMemento pop() {
        int lastIndex = mementos.size() - 1;
        EditorMemento lastMemento = mementos.get(lastIndex);
        mementos.remove(lastIndex);
        return lastMemento;
    }

}

5.4 testMemento

/**
 * @author Created by njy on 2023/7/2
 * 备忘录模式测试类
 */
@SpringBootTest
public class TestMemento {

    @Test
    void testMemento(){
        //创建文本编辑器(源发器)
        Editor editor = new Editor();
        //创建管理者
        History history = new History();
        // 编辑文本并保存状态
        editor.setContent("Hello");
        history.push(editor.createMemento());

        // 编辑更多文本并再次保存状态
        editor.setContent("Hello, Java!");
        history.push(editor.createMemento());

        editor.setContent("Hello,world!");
        System.out.println("当前内容: " + editor.getContent());

        // 恢复之前的状态
        editor.restoreMemento(history.pop());
        System.out.println("恢复后上一次内容: " + editor.getContent());

        editor.restoreMemento(history.pop());
        System.out.println("恢复后上二次内容: " + editor.getContent());
    }
}

六、总结

备忘录模式提供了一种灵活的机制来保存和恢复对象的状态,对于需要撤销、恢复或者状态管理的场景非常有用。然而,它也可能引起较大的内存占用和一定的性能开销,需要在使用之前慎重考虑。以下场景可以作为参考:

  • 撤销和恢复功能:可以通过保存对象的历史状态来实现撤销和恢复功能,比如文本编辑器、绘图应用程序或任务管理器。
  • 版本控制:如果你的应用程序需要跟踪对象状态的历史记录,并支持版本控制功能,备忘录模式可以帮助实现这种需求。例如,可以使用备忘录模式来实现文档的版本控制。
  • 多阶段事务:备忘录模式可以用于实现多阶段事务的状态管理。在一个事务中,可能需要保存中间状态,以便在需要时回滚到之前的状态。

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

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

相关文章

java常见算法篇【完整版】

14-常见算法 基本查找/顺序查找 从0索引依次向后查找 二分查找/折半查找 前提条件&#xff1a;数组中的数据必须是有序的核心逻辑&#xff1a;每次排除一半的查找范围 package io.xiaoduo.arithmetic;public class Test1 {public static void main(String[] args) {int[…

2023年10个最佳商业WordPress主题(经过测试和专家挑选)

正在寻找最好的商业WordPress主题&#xff1f; 为了帮助您找到适合您业务的完美主题&#xff0c;我们浏览并测试了15个最受欢迎的商业WordPress主题……然后将列表缩减为10个&#xff0c;为您提供最好的。 您需要制作一个成功的商业网站&#xff0c;以激发对潜在客户的信任并…

哪个平板电脑触控笔比较好用?便宜好用的触控笔测评

对于现在的iPad用户来说&#xff0c;苹果原装的Pencil绝对是最好的电容笔选择。但因为价格太高&#xff0c;很多人都买不起。所以&#xff0c;在实际应用中&#xff0c;如何选择一个具有高性能高性价比的电容笔就显得尤为重要。本人是一名“苹果粉”&#xff0c;又是一个老资格…

力扣方法总结-----动态规划

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、动态规划二、动态规划五部曲1.确定DP数组的含义2.确定递推公式3.确定初始值4.确定遍历顺序5.举例推导DP数组&#xff0c;打印程序中DP数组日志 三、例子 一、动…

Day 58-59 Naive Bayes算法

代码&#xff1a; package dl;import java.io.FileReader; import java.util.Arrays; import java.util.Random;import weka.core.*;/*** The Naive Bayes algorithm.*/public class NaiveBayes {/*** An inner class to store parameters.*/private class GaussianParameters…

el-tree 展开指定层级 节点

示例&#xff1a;只展开一级节点 代码实现&#xff1a; element UI 文档 html代码 defaultExpandedArr 是重点 需要加node-key <el-tree:props"defaultProps":data"treeData":default-expanded-keys"defaultExpandedArr"node-key"id&q…

第十六章Java多线程常见模式

文章目录 同步模式之保护性暂停带超时版 GuardedObjectjoin 原理多任务版 GuardedObject 异步模式之生产者/消费者模式标准库中的阻塞队列阻塞队列的实现加锁实现 生产者消费者模型的作用是什么 同步模式之保护性暂停 定义 即 Guarded Suspension&#xff0c;用在一个线程等待…

LeetCode_链表_中等_445.两数相加 II

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给你两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数字都不会以零开头。 …

C#异常总结

C#异常总结 定义Try语句异常类创建用户自定义异常搜索调用栈的示例异常抛出 定义 程序中的运行时错误&#xff0c;它违反一个系统约束或应用程序约束&#xff0c;或出现了在正常操作时未预料的情形。 Try语句 指明被异常保护的代码块&#xff0c;并提供代码以处理异常。try由…

ICC2:fixed和locked有什么不同?

如题&#xff0c;physical status中locked与fixed有很多小伙伴会搞混&#xff0c;从实用性的角度来讲这两个并没有什么区别&#xff0c;一是工具都不会更改object这两种属性&#xff0c;二是工具都不会在优化过程中移除这两个属性的object。 所以&#xff0c;唯一的区别在于lo…

【JUC-4】线程池实战应用

线程池 线程池创建方式 Executors创建线程池(不推荐) JDK提供的工具类Execurtors创建线程池(不推荐), 列举几个Executors中创建线程池的方法; 查看Executors的源代码发现, 它创建线程池也是通过 new ThreadPoolExecutor() 来创建线程池的. 当然其中有一些特殊的线程池也不是…

Moka AI产品后观察:HR SaaS迈进AGI时代

在AI这条路上&#xff0c;Moka已经走了很远。如今的Moka Eva是在此前AI模型基础上的更进一步。未来AGI时代&#xff0c;HR SaaS会有更多可能性。 出品|产业家 在AI潮水里&#xff0c;Moka正在加速快跑。 在6月28日的2023夏季新品发布会上&#xff0c;国内首个AI原生HR Saa…

流量卡收货地就是归属地,这是什么意思呢?

我们在网上申请流量卡时&#xff0c;会比较关注流量卡归属地这一问题&#xff0c;据小编了解&#xff0c;目前网上的流量卡归属地有两种模式&#xff0c;接下来&#xff0c;小编一一为大家介绍一下&#xff0c;大家可以根据自己的情况来选择。 ​ 在中国的手机号码都有固定的区…

【MySQL】备份数据(导出数据 / 导入数据)

&#x1f3af;导出数据 1、使用 SELECT ... INTO OUTFILE 语句导出数据 SELECT...INTO OUTFILE 是 MySQL 用于导出数据的语句&#xff0c;它允许将查询结果保存到指定的文件中。 该语句的基本语法如下&#xff1a; SELECT column1, column2, ... INTO OUTFILE file_path …

Kotlin~Template模版方法模式

概念 定义算法骨架、代码模版 角色介绍 Abstract ClassConcrete Class UML 代码实现 abstract class Game {protected abstract fun initialize()protected abstract fun startPlay()protected abstract fun endPlay()// 模版fun play(){initialize()startPlay()endPlay()…

Spring面试题--Spring中事务失效的场景有哪些

Spring中事务失效的场景有哪些&#xff1f; 异常捕获处理 Transactional public void update(Integer from, Integer to, Double money) {try {//转账的用户不能为空Account fromAccount accountDao.selectById(from);//判断用户的钱是否够转账if (fromAccount.getMoney() - …

idea运行项目时右下角一直提示Lombok requires enabled annotation processing

出现这个错误是因为使用了Lombok插件的原因&#xff0c;可能是安装时候没有配置好 Lombok requires enabled annotation processing&#xff1a;翻译过来就是Lombok 需要启用注释处理 解决方案 File -> Settings ->Build,Execution,Deployment -> Compiler ->An…

35岁程序员现状,太真实!

“未来每年&#xff0c;我们将会为社会输送1000名工作10年以上的人才。” 这是之前马云在演讲中提到的关于阿里巴巴这样的大厂老员工的问题。总的来讲就是——“毕业”。 也经常能够看到在各个平台有程序员讲到自己35岁的焦虑。 之前&#xff0c;在某平台上就有一个有意思的…

Redis主从复制模式3

谋权篡位 假设在一个Redis集群中&#xff0c;有一台主机和两台从机构成一个Redis集群。此时因外部原因&#xff0c;导致主机宕机&#xff0c;俗话说 “国不可⼀一日无君&#xff0c;军不可一日无帅”&#xff0c;那么需要从剩余的两台从机中再次选出一台主机&#xff0c;从而来…

【小沐学Unity3d】Unity插件之绳索模拟Obi Rope

文章目录 1、简介2、安装3、示例测试3.1 Chains3.2 Crane3.3 ElectricalWires3.4 FreightLift3.5 Rocker3.6 RopeAndJoints3.7 RopeShowcase 4、简单测试结语 1、简介 https://assetstore.unity.com/packages/tools/physics/obi-rope-55579 Obi 是一款基于粒子的高级物理引擎…