设计模式之备忘录模式 - 简书

news2024/12/20 2:53:58

备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。

解决方案

我们刚才遇到的所有问题都是封装 “破损” 造成的。 一些对象试图超出其职责范围的工作。 由于在执行某些行为时需要获取数据, 所以它们侵入了其他对象的私有空间, 而不是让这些对象来完成实际的工作。

备忘录模式将创建状态快照 (Snapshot) 的工作委派给实际状态的拥有者_原发器_ (Originator) 对象。 这样其他对象就不再需要从 “外部” 复制编辑器状态了, 编辑器类拥有其状态的完全访问权, 因此可以自行生成快照。

模式建议将对象状态的副本存储在一个名为_备忘录_ (Memento) 的特殊对象中。 除了创建备忘录的对象外, 任何对象都不能访问备忘录的内容。 其他对象必须使用受限接口与备忘录进行交互, 它们可以获取快照的元数据 (创建时间和操作名称等), 但不能获取快照中原始对象的状态。

这种限制策略允许你将备忘录保存在通常被称为_负责人_ (Caretakers) 的对象中。 由于负责人仅通过受限接口与备忘录互动, 故其无法修改存储在备忘录内部的状态。 同时, 原发器拥有对备忘录所有成员的访问权限, 从而能随时恢复其以前的状态。

在文字编辑器的示例中, 我们可以创建一个独立的历史 (History) 类作为负责人。 编辑器每次执行操作前, 存储在负责人中的备忘录栈都会生长。 你甚至可以在应用的 UI 中渲染该栈, 为用户显示之前的操作历史。

当用户触发撤销操作时, 历史类将从栈中取回最近的备忘录, 并将其传递给编辑器以请求进行回滚。 由于编辑器拥有对备忘录的完全访问权限, 因此它可以使用从备忘录中获取的数值来替换自身的状态。

备忘录模式结构

基于嵌套类的实现,该模式的经典实现方式依赖于许多流行编程语言 (例如 C++、 C# 和 Java) 所支持的嵌套类。

原发器 (Originator) 类可以生成自身状态的快照, 也可以在需要时通过快照恢复自身状态。

备忘录 (Memento) 是原发器状态快照的值对象 (value object)。 通常做法是将备忘录设为不可变的, 并通过构造函数一次性传递数据。

负责人 (Caretaker) 仅知道 “何时” 和 “为何” 捕捉原发器的状态, 以及何时恢复状态。

负责人通过保存备忘录栈来记录原发器的历史状态。 当原发器需要回溯历史状态时, 负责人将从栈中获取最顶部的备忘录, 并将其传递给原发器的恢复 (restoration) 方法。

在该实现方法中, 备忘录类将被嵌套在原发器中。 这样原发器就可访问备忘录的成员变量和方法, 即使这些方法被声明为私有。 另一方面, 负责人对于备忘录的成员变量和方法的访问权限非常有限: 它们只能在栈中保存备忘录, 而不能修改其状态。

JAVA 示例代码

import java.util.*;

public class MementoPattern {

    public static void main(String\[\] args) {

        Caretaker caretaker = new Caretaker();

        Originator originator = new Originator();

        originator.setState("1024");

        Memento backup1 = originator.createMemento();

        caretaker.addMemento(backup1);

        originator.setState("2048");

        Memento backup2 = originator.createMemento();

        caretaker.addMemento(backup2);

        originator.setState("4096");

        Memento backup3 = originator.createMemento();

        caretaker.addMemento(backup3);

        System.out.println(originator.getState());

        caretaker.showMemento();

        Memento memento1 = caretaker.getMemento(2);

        originator.setMemento(memento1);

        System.out.println("根据第2次备份还原之后的状态为:" + originator.getState());

    }

}

class Originator { // 原发器

    private String state;

    public void setState(String state) {

        this.state = state;

    }

    public String getState() {

        return state;

    }

    public Memento createMemento() {

        return new Memento(state);

    }

    public void setMemento(Memento memento) {

        state = memento.getState();

    }

}

class Memento { // 备忘录

    private String state;

    public Memento(String state) {

        this.state = state;

    }

    public String getState() {

        return state;

    }

}

class Caretaker { // 管理者

    private List<Memento> mementoList = new ArrayList<>();

    public void addMemento(Memento memento) {

        mementoList.add(memento);

    }

    public Memento getMemento(int index) {

        // 判断参数是否合法

        if (index >= 1 && index <= mementoList.size()) {

            return mementoList.get(index - 1);

        }

        return null;

    }

    public void showMemento() {

        int cnt = 1;

        // for (遍历对象类型 对象名 : 遍历对象)

        for (Memento memento : mementoList) {

            System.out.println("第" + cnt + "次备份,状态为:" + memento.getState());

            cnt ++ ;

        }

    }

}

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

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

相关文章

ipv6学习笔记221029

IPv6是英文“Internet Protocol Version 6”&#xff08;互联网协议第6版&#xff09;的缩写 ipv6的长度有128位, ipv4的长度是32位 ipv6以冒号:分隔 , ipv4以点.分隔 8个16位等于128位 , 4个十六进制表示16位(一个16进制表示4位) ipv6的128位 由 8 个 16位 16bit 组成 每…

【LeetCode】【两个数组的交集】

力扣 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a;num…

基于MATLAB的指纹识别算法仿真实现

目录 一、理论基础 二、核心程序 三、测试结果 一、理论基础 在指纹图像预处理部分&#xff0c;论文对预处理的各个步骤包括规格化、图像分割、中值滤波、二值化、细化等以及各个步骤的方法进行了深入的分析和研究&#xff0c;选择了一种图像预处理方案。在指纹特征提取部分…

基于javaweb的医疗挂号管理系统(java+springboot+freemarker+layui+mysql)

基于javaweb的医疗挂号管理系统(javaspringbootfreemarkerlayuimysql) 运行环境 Java≥8、MySQL≥5.7 开发工具 eclipse/idea/myeclipse/sts等均可配置运行 适用 课程设计&#xff0c;大作业&#xff0c;毕业设计&#xff0c;项目练习&#xff0c;学习演示等 功能说明 基…

幼儿园小程序实战开发教程(终篇)

我们已经写了四篇教程&#xff0c;涵盖了需求分析及各个页面&#xff0c;本篇是我们的最终篇。 咨询信息 我们小程序需要收集家长和孩子的信息&#xff0c;为此我们也规划了数据源。如果按照传统开发思路&#xff0c;那我们是要依次实现信息采集的每个字段&#xff0c;然后再…

<Linux系统复习>文件描述符

一、本章重点 1、进程和打开文件的关系 2、简单复习c语言文件操作 3、介绍系统调用&#xff1a;open、clos、write、read 4、理解文件描述符 5、文件描述符分配规则 6、理解stdin、stdout、stderr与fd的关系 7、理解linux下一切皆文件 8、理解重定向的本质 9、理解stdin和stdou…

《吉师作业》(1)之我是web手为啥让我学C

前言 &#x1f340;作者简介&#xff1a;吉师散养学生&#xff0c;为挣钱努力拼搏的一名小学生。 &#x1f341;个人主页&#xff1a;吉师职业混子的博客_CSDN博客-python学习,HTML学习,清览题库--C语言程序设计第五版编程题解析领域博主 &#x1fad2;文章目的&#xff1a;我不…

freeRTOS学习(二)

堆内存管理 先决条件 FreeRTOS是作为一组C源文件提供的&#xff0c;因此成为一个合格的C程序员是使用FreeRTOS的先决条件。 动态内存分配及其与FreeRTOS的相关性 内核对象&#xff1a;如任务、队列、信号量和事件组。为了使FreeRTOS尽可能易于使用&#xff0c;这些内核对象不…

科普一下MTU是什么,如何设置MTU

欢迎来到东用知识小课堂&#xff0c;下面我们就来科普一下一下MTU是什么&#xff0c;如何设置MTUMTU是最大传输单元的意思&#xff0c;代指一类通讯协议某一层上所能通过的最大数据包大小(以byte为单位)。最大传输单元这一主要参数一般与串行通讯接口相关(网络接口卡、串口等)。…

【Vue实用功能】彻底搞懂Vue中的Mixin混入

前言 有些小伙伴接手别人的Vue项目时&#xff0c;看到里面有个Mixin文件夹&#xff0c;可能会云里雾里的状态&#xff0c;今天我们来好好聊聊Mixin&#xff0c;争取以后不再云里雾里。 一、什么是Mixins&#xff1f; Mixins(混入)&#xff1a;当我们存在多个组件中的逻辑或者…

MySQL总结

文章目录一.SQL语句简介1.什么是SQL&#xff1f;2.SQL分类二.MySql常用数据类型三.数据库操作1.创建数据库2.查询和删除数据库3.备份/恢复数据库四.表操作1.创建表2.修改/查看表五.CRUD语句1.Insert语句2.Delete语句3.Update语句4.Select语句五.函数1.统计函数count2.字符串相关…

for in和for of

文章目录二者在什么情况下可以使用for ... in什么是可枚举的属性&#xff1f;for...of什么是可迭代的数据&#xff1f;总结二者在什么情况下可以使用 for … in 可以用在可枚举的数据&#xff0c;如&#xff1a; 对象数组&#xff08;循环的是索引&#xff09;字符串 什么是…

ESP8266-Arduino网络编程实例-发送邮件(基于SMTP)

发送邮件(基于SMTP) 本文将演示如何使用ESP8266发送邮件。实例中将使用SMTP(Simple Mail Transfer Protocol)协议通QQ邮箱向指定邮箱发送邮件。 1、设置QQ邮箱第三方服务 1)第一步:注册一个QQ邮箱 2)第二步:开启QQ邮箱的第三方服务 1、硬件准备 ESP8266 NodeMCU开发…

高通Android随身WIFI屏蔽商家远程控制断网

部分随身WIFI商家后台会监测用户是否使用的是自家的eSIM,若使用了外置卡槽或eSIM的ICCID改变就会断网,主要表现是先联网后突然变成飞行模式,或联网后开热点变飞行模式。这就是商家后台做了监测,检测到异常就断网。我们的主要解决思路就是禁止随身wifi连接商家的远程服务器,…

pytorch中一维卷积,二维卷积,三维卷积,层次特征注意力

一维卷积 一维卷积操作常用作文本数据或者序列数据的处理。这里以文本数据为例进行讲解。 下图左边是一个文本矩阵,是将这句话‘I like this movie very much!’转换为计算机可以处理的语言。对于宽度,可以认为是词向量的维度,高度可以表示为这个句子的最大长度,从这里可…

上手Python之set(集合)

为什么使用集合 我们目前接触到了列表、元组、字符串三个数据容器了。基本满足大多数的使用场景。 为何又需要学习新的集合类型呢&#xff1f; 通过特性来分析&#xff1a; 列表可修改、支持重复元素且有序 元组、字符串不可修改、支持重复元素且有序 有没有看出一些局限&…

JavaEE在线学习系统的设计与实现

目 录 摘 要 i Abstract ii 第1章 概论 1 1.1 课题背景 1 1.2 课题意义 2 1.3开发工具及技术 2 1.3.1 MyEclipse 2 1.3.2 ToMcat 2 1.3.3 SqlServer 2 1.3.4 JSP 3 1.3.5 Servlet 3 第2章 可行性分析及总体设计原则 5 2.1可行性分析 5 2.1.1技术可行性 5 2.1.2经济可行性 5 2.1…

Python - Numpy库的使用(简单易懂)

目录 numpy多维数组——数组的创建 1、array函数创建数组对象 2、通过arange、linspace函数创建等差数组对象 3、通过logspace函数创建等比数列数组 函数 zeros ones diag eye full numpy多维数组——生成随机数 函数 seed rand randn randint 函数 binomial normal 和…

【算法篇-搜索与图论】适合算法入门小白理解的深度优先搜索(DFS )以及解决全排列数字

目录1.什么是深度优先搜索&#xff08;DFS&#xff09;2.结合例子看DFS2.1 全排列数字结语该文章部分内容摘抄自 啊哈磊老师的《啊哈&#xff01;算法》 一本对算法新手非常友好的书&#xff0c;非常推荐新手去阅读&#xff01; 1.什么是深度优先搜索&#xff08;DFS&#xff0…

【阿里云】短信服务

目录 1. 前置技术&#xff1a;阿里大鱼 1.1 概述 1.2 开通 1.3 签名管理 1.3.1 签名概述 1.3.2 添加签名 1.3.3 使用 1.4 模板管理 1.4.1 模板概述 1.4.2 添加模板 1.4.3 使用 1.5 在线文档 1.5.1 打开在线文档 1.5.2 使用在线文档 1.6 使用工具类发送短信 1.7…