备忘录模式-撤销功能的实现

news2025/1/10 22:31:11

 在idea写代码的过程中,会经常用到一个快捷键——“crtl + z”,即撤销功能。“备忘录模式”则为撤销功能提供了一个设计方案。

1 备忘录模式

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

图 备忘录UML

Originator:原发器,一个需要保存内部状态的普通类,可以创建一个备忘录,也可通过备忘录来恢复其在某个时候的状态。

Memento:备忘录,存储原发器的内部状态。除了原发器本身及管理者类外,备忘录不能直接供其他类使用。

CareTaker:管理者,负责保存备忘录,但不能对备忘录内容进行操作或检查,无须知道备忘录的细节。

@Data
public class IdeaCodeOriginator {

    private String code;

    private Integer position;

    public IdeaCodeOriginator(String code, Integer position) {
        this.code = code;
        this.position = position;
    }

    public void restoreMemento(IdeaCodeMemento memento) {
        this.code = memento.getCode();
        this.position = memento.getPosition();
    }

    public IdeaCodeMemento createMemento() {
        return new IdeaCodeMemento(code,position);
    }

}

@Data
public class IdeaCodeMemento {

    private String code;

    private Integer position;

    public IdeaCodeMemento(String code, Integer position) {
        this.code = code;
        this.position = position;
    }
}

public class CareTaker {

    private final Stack<IdeaCodeMemento> mementoStack = new Stack<>();

    public IdeaCodeMemento getMemento(int num) {
        IdeaCodeMemento memento = null;
        while (num-- > 0 && !mementoStack.isEmpty()) {
            memento = mementoStack.pop();
        }
        return mementoStack.isEmpty() ? memento : mementoStack.pop();
    }

    public void saveMemento(IdeaCodeMemento memento) {
        mementoStack.push(memento);
    }

}

public class IdeaCodeEditor {

    public static void main(String[] args) {
        CareTaker careTaker = new CareTaker();

        IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);
        careTaker.saveMemento(originator1.createMemento());

        IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);
        careTaker.saveMemento(originator2.createMemento());

        IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);
        careTaker.saveMemento(originator3.createMemento());

        IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);
        careTaker.saveMemento(originator4.createMemento());

        //撤回到2步前
        originator4.restoreMemento(careTaker.getMemento(2));
        System.out.println(originator4); // IdeaCodeOriginator(code=word, position=2)

    }

}

1.1 优化

1)要避免其他类操作或者检查备忘录的内容。

2)备忘录管理者应该具有通用性。

public interface Memento {
}

@Data
public class IdeaCodeOriginator {

    private String code;
    private Integer position;

    public IdeaCodeOriginator(String code, Integer position) {
        this.code = code;
        this.position = position;
    }

    @Data
    private static class InnerMemento implements Memento {
        private String code;
        private Integer position;

        public InnerMemento(String code, Integer position) {
            this.code = code;
            this.position = position;
        }
    }

    public Memento createMemento() {
        return new InnerMemento(code,position);
    }

    public void restoreMemento(Memento memento) throws Exception {
        if (memento instanceof InnerMemento) {
            InnerMemento innerMemento = (InnerMemento) memento;
            this.code = innerMemento.getCode();
            this.position = innerMemento.position;
        } else {
            throw new Exception("类型错误");
        }
    }

}

public class CareTaker<T> {

    Stack<T> stack = new Stack<>();

    public T getMemento(int num) {
        T memento = null;
        while (num-- > 0 && !stack.isEmpty()) {
            memento = stack.pop();
        }
        return stack.isEmpty() ? memento : stack.pop();
    }

    public void saveMemento(T memento) {
        stack.push(memento);
    }

}

public class IdeaCodeEditor2 {

    public static void main(String[] args) throws Exception {

        CareTaker<Memento> objectCareTaker = new CareTaker<>();

        IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);
        objectCareTaker.saveMemento(originator1.createMemento());

        IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);
        objectCareTaker.saveMemento(originator2.createMemento());

        IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);
        objectCareTaker.saveMemento(originator3.createMemento());

        IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);
        objectCareTaker.saveMemento(originator4.createMemento());

        originator4.restoreMemento(objectCareTaker.getMemento(3)); // IdeaCodeOriginator(code=hello, position=1)
        System.out.println(originator4);

    }

}

2 优缺点

如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。

优点:1)它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤;

缺点:1)资源消耗过大。如果要保存的原发器类的成员变量太多,就不可避免地占用大量的储存空间。每保存一次对象状态都需要消耗一定的系统资源。

3 适用场景

1)保存一个对象在某时刻的全部或部分状态,实现撤销操作。

2)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态实现细节暴露给外界对象。

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

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

相关文章

关于职业规划的学习经验总结

目录 前言 结构化思考 思考快与慢 积极主动 以终为始 要事第一 前言 每一年的年中或者年终都有一场很重要的活动就是述职,需要花费一定精力投入,那么述职是一种形式吗?当然不是。述职是一种组织的管理手段和机制,通过这种机制除了对战略方向和项目进度进行把控,还对…

chatgpt 4V 识图功能

1.获取图片的sig和file_id 2e0edc6e489ed13a3f32f0dd87527d77.jpg是本地图片的名字 头部认证信息自己F12 抓取 1.获取图片的sighttps://chat.openai.com/backend-api/filesAuthorization:Bearer eyJhbGc****************5V-lztYwLb9hr6LP7g Cookie: **********************…

set_data_check做等长线

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 常常会遇见2out的多个信号需要做等长&#xff0c;下面分享一个脚本。 set port1_coll [get_ports out[*]] set port2_coll [get_ports out[*]] foreach_in_collection temp1 $…

ChatGPT教你5分钟解锁国际象棋技能

国际象棋是一种很好玩的棋类游戏&#xff0c;走法和规则与中国象棋有所区别。如果想要快速入门&#xff0c;可以把ChatGPT当做私人教练&#xff0c;提出这些问题&#xff1a; ●作为零基础的初学者&#xff0c;学习国际象棋的最佳方法是什么&#xff1f;如何快速入门&#xff…

计算机保研推免面试复习大纲(数学+408)

目录 线性代数概率论高等数学信号与系统离散数学操作系统计算机网络计算机组成数据结构算法编译原理C杂项 线性代数 怎么求逆矩阵 逆矩阵&#xff1a; A A − 1 E AA^{-1}E AA−1E&#xff0c;伴随矩阵&#xff1a; A A ∗ A ∗ A ∣ A ∣ E AA^{*}A^{*}A|A|E AA∗A∗A∣A∣…

算法通关村第一关-链表白银经典问题笔记

大家好今天来写第一关的白银挑战-链表经典问题. 两个链表的第一个公共结点 这是一道经典的链表问题 : 输入两个无环的单向链表&#xff0c;找出它们的第一个公共结点&#xff0c;如果没有公共节点则返回空。 牛客NC66 : 剑指offer56 : 分析 : 屡试不爽的方法: 将常用数据…

第15章 SpringBoot

所有的流程逻辑原理都是针对2.3.2.RELEASE版本 15.1 谈谈你对微服务架构演进的理解 难度:★ 重点:★ 白话解析 还是串主线,在串主线的过程中发现问题,解决问题。主线的入口:随着业务的逻辑越来越复杂,架构再不断升级演进,先理解架构的演进。 这道题参考了:企业IT架构转…

引领虚拟化技术新潮流:VMware Fusion Pro for Mac/win中文版

当谈论虚拟机时&#xff0c;很多人可能会对其有所了解&#xff0c;但并不一定清楚它的具体作用和优势。在这篇文章中&#xff0c;我们将带您走进虚拟机的世界&#xff0c;并深入了解VMware Fusion Pro这一专业虚拟化解决方案的独特魅力。 虚拟机是一种模拟真实计算机环境的软件…

黑马mysql教程笔记(mysql8教程)基础篇——函数(字符串函数、数值函数、日期函数、流程函数)

参考文章1&#xff1a;https://www.bilibili.com/video/BV1Kr4y1i7ru/ 参考文章2&#xff1a;https://dhc.pythonanywhere.com/article/public/1/ 文章目录 基础篇函数字符串函数常用函数使用示例实例&#xff1a;更新已有的所有员工号&#xff0c;使其满足5位数长度&#xff…

抓包工具charles修改请求和返回数据

数据篡改的主要使用场景&#xff1a; &#xff08;1&#xff09;mock场景&#xff0c;mock入参和返回值参数&#xff0c;实现mock测试 &#xff08;2&#xff09;安全测试&#xff0c;对于支付金额等比较重要的字段&#xff0c;可以修改请求参数来进行安全测试 1.首先选择要…

Flink的算子列表状态的使用

背景 算子的列表状态是平时比较常见的一种状态&#xff0c;本文通过官方的例子来看一下怎么使用算子列表状态 算子列表状态 算子列表状态支持应用的并行度扩缩容&#xff0c;如下所示: 使用方法参见官方示例&#xff0c;我加了几个注解&#xff1a; public class Bufferin…

IP网络广播景区广播广播系统

IP网络广播景区广播广播系统 IP网络广播系统草坪音箱景区系统防水石头,草坪音箱的应用 SV-7045V是深圳锐科达电子有限公司的一款防水网络草坪音箱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;可达到功率20W。常用场景…

秋日有感之秋诉-于光

诗&#xff1a;于光 秋风扫叶枝不舍&#xff0c; 叶落随风根欢唱。 秋日穿云不入眼&#xff0c; 云亦婆娑诉余年。

卡片翻转效果的实现思路

卡片翻转效果的实现思路 HTML 基础布局 <div class"card"><img class"face" src"images/chrome_eSCSt8hUpR.png" /><p class"back"><span>背面背景</span></p> </div>布局完成后如下所示…

点云处理【二】(点云滤波)

点云滤波 第一章 点云数据采集 第二章 点云滤波 1. 为什么要滤波&#xff1f; 通常我们获取的点云数据中包含噪声&#xff0c;噪声会影响点云的特征提取、配准和语义处理。 点云需要处理的主要情况包括: 数据量过大&#xff0c;不易于处理&#xff0c;需要进行下采样 通常由…

MySQL学习(四)——事务与存储引擎

文章目录 1. 事务1.1 概念1.2 事务操作1.2.1 未设置事务1.2.2 控制事务 1.3 事务四大特性1.4 并发事务问题1.5 事务隔离级别 2. 存储引擎2.1 MySQL体系结构2.2 存储引擎2.3 存储引擎的特点2.3.1 InnoDB2.3.2 MyISAM2.3.3 Memory2.3.4 区别和比较 1. 事务 1.1 概念 事务 是一组…

如何实现前端单页面应用(SPA)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

(三十三)geoserver源码添加新的数据存储

1.添加新的数据存储 如下图所示&#xff0c;为我们经常操作的添加数据存储的界面。 可以看到这个代码在如下的位置。在这样的代码中实现跳转。header.add(new BookmarkablePageLink("addNew", NewDataPage.class)); public class StorePage extends GeoServerSecur…

Notes/Domino 14 Early Access Drop3发布

大家好&#xff0c;才是真的好。 其实上周&#xff0c;就是国庆假期的时候&#xff0c;HCL Notes/Domino 14 Early Access Drop3&#xff08;以下简称EA3&#xff09;就已经发布&#xff0c;而且和传说中的一样&#xff0c;带来了数项惊人的新特性。 我们先讲讲这一版本新特性…