设计模式-备忘录模式(Memento)
设计模式-备忘录模式(Memento)
- 一、备忘录模式概述
- 1.1 什么是备忘录模式
- 1.2 简单实现备忘录模式
- 1.3 使用备忘录模式的注意事项
- 二、备忘录模式的用途
- 三、备忘录模式实现方式
- 3.1 基于数组的备忘录实现方式
- 3.2 基于集合的备忘录实现方式
- 3.3 基于HashMap的备忘录实现方式
- 3.4 基于序列化的备忘录实现方式
一、备忘录模式概述
1.1 什么是备忘录模式
备忘录模式(Memento Pattern)是一种行为型设计模式,它允许你捕获对象的内部状态,并在需要时恢复该状态,而无需暴露该对象的实现细节。所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态。
这种模式的名字可能对一些人来说稍微有点陌生,但其另一个名字快照模式可能会让人觉得更为熟悉。备忘录模式的适用场景包括:需要保存和恢复数据的场景,例如,编辑文档时需要撤销操作;需要避免重复计算的场景,例如,斐波那契数列;以及需要将一个对象的状态作为参数传递给其他对象的场景,例如,从数据库中查询数据。
1.2 简单实现备忘录模式
备忘录模式是一种行为型设计模式,它允许在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态。
下面是一个简单的Java实现备忘录模式的例子:
首先,我们创建一个原始类(Originator):
public class Originator {private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}public Memento saveStateToMemento() {return new Memento(state);}public void getStateFromMemento(Memento memento) {state = memento.getState();}
}
然后,我们创建一个备忘录类(Memento):
public class Memento {private String state;public Memento(String state) {this.state = state;}public String getState() {return state;}
}
接下来,我们创建一个负责管理备忘录的类(Caretaker):
import java.util.ArrayList;
import java.util.List;public class Caretaker {private List<Memento> mementoList = new ArrayList<>();public void add(Memento state) {mementoList.add(state);}public Memento get(int index) {return mementoList.get(index);}
}
最后,我们在主函数中测试备忘录模式:
public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("状态1");caretaker.add(originator.saveStateToMemento());originator.setState("状态2");caretaker.add(originator.saveStateToMemento());originator.setState("状态3");caretaker.add(originator.saveStateToMemento());System.out.println("当前状态: " + originator.getState());originator.getStateFromMemento(caretaker.get(0));System.out.println("恢复后的状态: " + originator.getState());}
}
运行结果:
当前状态: 状态3
恢复后的状态: 状态1
1.3 使用备忘录模式的注意事项
-
1、备忘录的保存和使用必须在同一个上下文中,不能将备忘录传递给其他对象。如果需要传递备忘录,可以使用Caretaker类来管理备忘录。
-
2、备忘录对象需要保存原始对象的内部状态,因此备忘录对象应该与原始对象具有相同的属性和方法。但是,备忘录对象不应该包含任何业务逻辑或行为。
-
3、如果原始对象的内部状态被修改,备忘录对象也需要相应地更新。因此,在保存备忘录之前,需要先调用原始对象的saveStateToMemento()方法。
-
4、如果需要恢复原始对象的内部状态,可以使用getStateFromMemento()方法。但是,需要注意的是,恢复后的状态可能不是最新的状态,因为原始对象可能在恢复状态之后又进行了修改。
-
5、备忘录模式适用于那些需要保存和恢复状态的场景,但不适用于所有场景。如果只需要保存和恢复单个状态,可以使用简单变量来实现;如果需要保存和恢复多个状态,可以使用数据结构(如数组或列表)来管理备忘录对象。
二、备忘录模式的用途
-
1、备忘录模式主要用于保存和恢复对象的状态,以便在需要时可以恢复到先前的状态。这种模式通常用于以下情况:
-
2、撤销操作:当一个操作序列可以被撤销时,可以使用备忘录模式来保存每个操作的结果,以便在需要时进行撤销。
-
3、跨层传递参数:当一个对象需要将其状态传递给另一个对象时,可以使用备忘录模式将该对象的状态保存在一个备忘录中,然后将备忘录传递给另一个对象。
-
4、避免重复计算:当一个对象的计算成本很高时,可以使用备忘录模式来保存其中间结果,以便在需要时可以直接使用这些结果,而不必重新计算它们。
-
5、测试和维护:当需要对一个对象进行单元测试或维护时,可以使用备忘录模式来保存其当前状态,以便在测试或维护完成后可以恢复到先前的状态。
三、备忘录模式实现方式
3.1 基于数组的备忘录实现方式
基于数组的备忘录实现方式可以通过以下步骤完成:
创建一个类,该类包含一个用于保存状态的数组。
在类中定义一个方法,该方法将对象的状态保存到数组中。
在类中定义另一个方法,该方法从数组中恢复对象的状态。
在需要保存和恢复状态的地方调用相应的方法。
以下是一个简单的示例代码:
public class Memento {private int[] state;public Memento(int[] state) {this.state = state;}public int[] getState() {return state;}
}public class Originator {private int[] state;public void setState(int[] state) {this.state = state;}public int[] getState() {return state;}public Memento saveStateToMemento() {return new Memento(state);}public void getStateFromMemento(Memento memento) {state = memento.getState();}
}public class Caretaker {private List<Memento> mementos = new ArrayList<>();public void add(Memento state) {mementos.add(state);}public Memento get(int index) {return mementos.get(index);}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState(new int[]{1, 2, 3});caretaker.add(originator.saveStateToMemento());originator.setState(new int[]{4, 5, 6});caretaker.add(originator.saveStateToMemento());originator.getStateFromMemento(caretaker.get(0)); // 恢复到第一个状态System.out.println(Arrays.toString(originator.getState())); // 输出 [1, 2, 3]}
}
在这个示例中,我们创建了一个Originator类来表示原始对象,一个Memento类来表示备忘录,一个Caretaker类来管理备忘录。在Main类的main方法中,我们创建了Originator和Caretaker对象,并使用它们来保存和恢复对象的状态。
3.2 基于集合的备忘录实现方式
基于集合的备忘录实现方式可以通过以下步骤完成:
创建一个类,该类包含一个用于保存状态的集合。
在类中定义一个方法,该方法将对象的状态添加到集合中。
在类中定义另一个方法,该方法从集合中恢复对象的状态。
在需要保存和恢复状态的地方调用相应的方法。
以下是一个简单的示例代码:
import java.util.ArrayList;
import java.util.List;public class Memento {private List<String> state;public Memento() {state = new ArrayList<>();}public void addState(String state) {this.state.add(state);}public String getState(int index) {return state.get(index);}
}public class Originator {private List<String> states;public Originator() {states = new ArrayList<>();}public void setState(String state) {states.add(state);}public String getState() {return states.get(states.size() - 1);}public Memento saveStateToMemento() {Memento memento = new Memento();memento.addState(getState());return memento;}public void getStateFromMemento(Memento memento) {int index = states.size() - 1;setState(memento.getState(index));}
}public class Caretaker {private List<Memento> mementos;public Caretaker() {mementos = new ArrayList<>();}public void add(Memento memento) {mementos.add(memento);}public Memento get(int index) {return mementos.get(index);}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("状态1");caretaker.add(originator.saveStateToMemento());originator.setState("状态2");caretaker.add(originator.saveStateToMemento());originator.getStateFromMemento(caretaker.get(0)); // 恢复到第一个状态System.out.println(originator.getState()); // 输出 "状态1"}
}
在这个示例中,我们创建了一个Memento类来表示备忘录,一个Originator类来表示原始对象,一个Caretaker类来管理备忘录。在Main类的main方法中,我们创建了Originator和Caretaker对象,并使用它们来保存和恢复对象的状态。
3.3 基于HashMap的备忘录实现方式
基于HashMap的备忘录实现方式可以通过以下步骤完成:
创建一个类,该类包含一个用于保存状态的HashMap。
在类中定义一个方法,该方法将对象的状态添加到HashMap中。
在类中定义另一个方法,该方法从HashMap中恢复对象的状态。
在需要保存和恢复状态的地方调用相应的方法。
以下是一个简单的示例代码:
import java.util.HashMap;public class Memento {private HashMap<String, Object> stateMap;public Memento() {stateMap = new HashMap<>();}public void addState(String key, Object value) {stateMap.put(key, value);}public Object getState(String key) {return stateMap.get(key);}
}public class Originator {private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}public Memento saveStateToMemento() {Memento memento = new Memento();memento.addState("state", state);return memento;}public void getStateFromMemento(Memento memento) {state = (String) memento.getState("state");}
}public class Caretaker {private ArrayList<Memento> mementoList;public Caretaker() {mementoList = new ArrayList<>();}public void addMemento(Memento memento) {mementoList.add(memento);}public Memento getMemento(int index) {return mementoList.get(index);}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("状态1");caretaker.addMemento(originator.saveStateToMemento());originator.setState("状态2");caretaker.addMemento(originator.saveStateToMemento());originator.setState((String) caretaker.getMemento(0).getState("state"));System.out.println("恢复后的状态: " + originator.getState()); // 输出 "恢复后的状态: 状态1"}
}
在这个示例中,我们创建了一个Memento类来表示备忘录,一个Originator类来表示原始对象,一个Caretaker类来管理备忘录。在Main类的main方法中,我们创建了Originator和Caretaker对象,并使用它们来保存和恢复对象的状态。
3.4 基于序列化的备忘录实现方式
基于序列化的备忘录实现方式可以通过以下步骤完成:
创建一个类,该类包含一个用于保存状态的私有成员变量。
为该类添加一个构造函数,用于初始化私有成员变量。
为该类添加一个序列化方法,用于将对象的状态保存到文件中。
为该类添加一个反序列化方法,用于从文件中恢复对象的状态。
在需要保存和恢复状态的地方调用相应的序列化和反序列化方法。
以下是一个简单的示例代码:
import java.io.*;class Memento implements Serializable {private String state;public Memento(String state) {this.state = state;}public String getState() {return state;}public void setState(String state) {this.state = state;}public void saveToFile(String fileName) {try {FileOutputStream fos = new FileOutputStream(fileName);ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(this);oos.close();fos.close();} catch (IOException e) {e.printStackTrace();}}public static Memento restoreFromFile(String fileName) {Memento memento = null;try {FileInputStream fis = new FileInputStream(fileName);ObjectInputStream ois = new ObjectInputStream(fis);memento = (Memento) ois.readObject();ois.close();fis.close();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}return memento;}
}public class Main {public static void main(String[] args) {Memento memento = new Memento("初始状态");System.out.println("当前状态: " + memento.getState());memento.setState("修改后的状态");System.out.println("修改后的状态: " + memento.getState());memento.saveToFile("memento.ser");Memento restoredMemento = Memento.restoreFromFile("memento.ser");System.out.println("恢复后的状态: " + restoredMemento.getState());}
}
在这个示例中,我们创建了一个名为Memento的类,它实现了Serializable接口。我们为这个类添加了一个私有成员变量state,以及一个构造函数、一个获取状态的方法、一个设置状态的方法、一个保存状态到文件的方法和一个从文件恢复状态的方法。在main方法中,我们创建了一个Memento对象,修改了它的状态,然后将它的状态保存到文件中。接着,我们从文件中恢复了这个对象的状态,并打印出来。
相关文章:
设计模式-备忘录模式(Memento)
设计模式-备忘录模式(Memento) 一、备忘录模式概述1.1 什么是备忘录模式1.2 简单实现备忘录模式1.3 使用备忘录模式的注意事项 二、备忘录模式的用途三、备忘录模式实现方式3.1 基于数组的备忘录实现方式3.2 基于集合的备忘录实现方式3.3 基于HashMap的备…...

【机器学习】正则化到底是什么?
先说结论:机器学习中的正则化主要解决模型过拟合问题。 如果模型出现了过拟合,一般会从两个方面去改善,一方面是训练数据,比如说增加训练数据量,另一方面则是从模型角度入手,比如,降低模型复杂…...
Rust5.2 Generic Types, Traits, and Lifetimes
Rust学习笔记 Rust编程语言入门教程课程笔记 参考教材: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community) Lecture 10: Generic Types, Traits, and Lifetimes lib.rs use std::fmt::Display;//Traits: …...
c 实用化的摄像头生成avi视频程序(加入精确的时间控制)
I时间控制是指:生成了n张图片帧用了多少时间m。帧率等于n/m。对应于头文件,m等于scale, n等于rate.为了精确,采用微秒计时。 I此程序生成的视频远好于ffmpeg,可能是此程序没有压缩数据原因吧。 现在的帧率不高,是因…...

Web后端开发_01
Web后端开发 请求响应 SpringBoot提供了一个非常核心的Servlet 》DispatcherServlet,DispatcherServlet实现了servlet中规范的接口 请求响应: 请求(HttpServletRequest):获取请求数据响应(HttpServletRe…...

二十、泛型(6)
本章概要 问题 任何基本类型都不能作为类型参数实现参数化接口转型和警告重载基类劫持接口 自限定的类型 古怪的循环泛型自限定参数协变 问题 本节将阐述在使用 Java 泛型时会出现的各类问题。 任何基本类型都不能作为类型参数 正如本章早先提到的,Java 泛型的…...

Java18新增特性
前言 前面的文章,我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16、Java17 的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 Java…...

springboot容器
1.主要指的是servlet容器 servlet组件由sevlet Filter Listener等 2.自动配置原理 通过ServletWebServerFactoryAutoConfiguration 配置这些内容 (自动配置类开始分析功能) conditionalOnclass开启条件 ServletRequest类 import导入嵌入式的tomcat Jetty等 这些是配置类&…...

Windows 10 下使用Visual Studio 2017 编译CEF SDK
1.下载CEF SDK 由于需要跑在32位的机器,所以选择下载32位的SDKCEF Automated Builds 选择 Current Stable Build (Preferred) ,这是当前稳定版本,CEF版本118 下载成功解压 2.下载编译工具 CMake 下载地址:CMake 配置CMake指向…...

数字货币swap交易所逻辑系统开发分析方案
随着数字货币市场的快速发展, Swap交易所已成为一种重要的交易方式。本文将对数字货币Swap交易所逻辑系统开发进行分析,并探讨其优势、开发难点和解决方案。 一、数字货币Swap交易所逻辑系统开发的优势 数字货币Swap交易所是一种点对点的交易方式&#x…...

spring boot中使用Bean Validation做优雅的参数校验
一、Bean Validation简介 Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),目前最新稳定版2.0.2(201…...

搜索引擎项目
认识搜索引擎 1、有一个主页、有搜索框。在搜索框中输入的内容 称为“查询词” 2、还有搜索结果页,包含了若干条搜索结果 3、针对每一个搜索结果,都会包含查询词或者查询词的一部分或者和查询词具有一定的相关性 4、每个搜索结果包含好几个部分&…...

7.外部存储器,Cache,虚拟存储器
目录 一. 外部存储器 (1)磁盘存储器 1.磁盘的组成 2.磁盘的性能指标 3.磁盘地址 4.硬盘的工作过程 5.磁盘阵列 (2)固态硬盘(SSD) 二. Cache基本概念与原理 三. Cache和主存的映射方式 ÿ…...

UITableView的style是UITableViewStyleGrouped
一般情况下,UITableViewStylePlain和UITableViewStyleGrouped是UITableView常用到的style, 之前都是用到的时候,遇到问题直接用度娘,差不多就够用了,今天在修复UI提出的间隙问题,来回改,总觉得…...

Java17新增特性
前言 前面的文章,我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15、Java16 的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 Java16新增特…...

VR全景技术在城市园区发展中有哪些应用与帮助
引言: 在数字化时代的浪潮中,虚拟现实(VR)全景技术逐渐融入各个领域,也为城市园区展示带来了全新的可能性。 一.VR全景技术简介 虚拟现实全景技术是一种通过全景图像和视频模拟真实环境的技术。通过相关设…...

在 SQL 中,当复合主键成为外键时应该如何被其它表引用
文章目录 当研究一个问题慢慢深入时,一个看起来简单的问题也暗藏玄机。在 SQL 中,主键成为外键这是一个很平常的问题,乍一看没啥值得注意的。但如果这个主键是一种复合主键,而另一个表又引用这个键作为它的复合主键,问…...

Ps:通过显示大小了解图像的打印尺寸
在 Photoshop 中,如果想了解文档窗口中的图像打印出来之后的实质大小,只要知道两个数值即可。 第一个数值是图像分辨率(也称“文档分辨率”)的大小,可在Ps菜单:图像/图像大小 Image Size对话框中查询或设置…...
Linux - 驱动开发 - watchdog - SMP机制下多核确活
说明 理论上:不管IC是单核还是多核,只要watchdog有被循环feed,就不会触发超时重启,因此watchdog在SMP机制下的多核环境显得比较宽松,只要任意核存活(喂狗)就不会重启设备。 实际情况 有客户反…...
概念解析 | LoRA:低秩矩阵分解在神经网络微调中的魔力
注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:基于低秩矩阵分解的神经网络微调方法LoRA LoRA:低秩矩阵分解在神经网络微调中的魔力 Low-Rank Adaptation of Large Language Models LoRA由如下论文提出,详细信息请参见论文原…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...