Java设计模式之备忘录模式
作者:理想万岁万万岁
一、介绍
备忘录模式(Memento Pattern),属于行为型设计模式。目的是用于保存一个对象在某一时刻的状态,以便于在将来某个时刻根据此状态恢复该对象。
在我们日常生活中,备忘录的使用十分频繁。比如,有一个事情我们完成了35%的进度,这时有另一件更重要的事情需要处理,那么我们需要对这个已完成35%的事情进行记录(做了哪些事情,做到什么程度等),当那个更重要的事情完成后,就可以根据记录的内容(做了哪些事情,做到什么程度等)继续处理这件事情,而不至于因为忘记处理进度而导致重复或疏漏,这个记录的过程就是备忘。
另一个十分鲜活的例子就是,我们经常在对一些东西进行计数时被其他人说话而打断,当你回答对方后自己却突然忘记数到哪里了,如果你在说话前已经数了相当长一段时间,那此时你可能不得不从0重新开始计数。当应用备忘录时,无论你的计数达到什么程度,在别人和你说话时,你先将当前计数保存记录下来,在谈话完成后,再继续计数即可,以此避免从0重新开始计数。
当我们系统中存在一个对象,
下面是备忘录模式的概念解释:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
二、应用举例
根据我们在介绍中的描述,我们应该明白了备忘录模式的本质其实就是对象状态的保存和读取。不难发现,备忘录模式的应用到处可见
几乎所有的软件
在我们使用的所有软件无论是桌面端还是网页端,只要有保存功能,就都是备忘录模式的体现。
比如,我们使用txt文本文档编辑文本,在编辑的过程中任意时刻我们都可以使用ctrl+s对其保存,当再次打开该txt文档时,展示的就是我们最后一次保存时的文本,这种备忘的介质就是硬盘。
再比如,我们在某一个网站中对个人信息进行编辑时,当按下保存按钮时,网页会发起网络请求,将我们编辑的个人信息发送到远程服务器,当再次打开个人信息页面进行查看或编辑时,网页会再次向远程服务器发起请求获取我们上一次保存个人信息。这种备忘的介质就是远程数据库。
java序列化
java的序列化和反序列化过程也是备忘录模式的体现。其中,序列化的过程就相当于对一个对象状态的保存,反序列化的过程就相当于对以保存的对象状态进行恢复。
三、基本角色
在标准的备忘录模式中,包含以下三个角色:
Memento
保存对象的内部状态。即备忘录本身。而既然是备忘录,自然有两个最基本的方法来保存和获取其内部保存的状态:getState()和setState()。
存储源发器对象的状态。备忘录对象可以包括一个或多个状态属性,源发器可以根据需要保存和恢复状态。
Originator
创建备忘录,并保存指定对象的状态。即备忘录管理者。作为备忘录的管理者,自然在其内部保存着多个备忘(mementoList)和对应的添加删除方法(add(memento)和remove(memento))。
需要保存和恢复状态的对象。它创建一个备忘录对象,用于存储当前对象的状态,也可以使用备忘录对象恢复自身的状态。
Caretaker
从备忘录中读取对象的状态并恢复对象。有了备忘录管理者,我们对备忘录的操作应转移到管理者上,通过备忘录管理者存取备忘录中的状态。
负责保存备忘录对象,但不能修改备忘录对象的内容。它可以存储多个备忘录对象,并决定何时将备忘录恢复给源发器。
注意:一般情况下,备忘录模式无需抽象组件,但究竟需不需要抽象类根据实际情况来定。
备忘录的通用UML图如下所示

四、代码演示
下面我们通过代码对上面基本角色的分析进行演示
备忘录类Memento
public class Memento {
// 对象某一时刻的状态
private String state;
// 获取对象的状态
public String getState() {
return state;
}
// 保存对象的状态
public void setState(String state) {
this.state = state;
}
}备忘录管理员类Originator
public class Originator {
// 备忘录集合
private final List<Memento> mementoList;
public Originator() {
// 对备忘录集合进行初始化
this.mementoList = new ArrayList<>();
}
// 保存对象某一状态到备忘录
public void saveState(String state) {
Memento memento = new Memento();
memento.setState(state);
mementoList.add(memento);
}
// 获取某一备忘录并将其移除
public Memento getMemento(int index) {
return mementoList.remove(index);
}
}读取状态类Caretaker
public class Caretaker {
// 备忘录管理者
private final Originator originator;
// 备忘录管理者的初始化
public Caretaker(Originator originator) {
this.originator = originator;
}
// 获取某个备忘录中对象的状态
public String getState(Integer index) {
return originator.getMemento(index).getState();
}
}客户端测试代码
public class MementoDemo {
public static void main(String[] args) {
// 将对象的状态交给备忘录管理员通过备忘录管理
Originator originator = new Originator();
originator.saveState("第一个字符串");
originator.saveState("第二个字符串");
originator.saveState("第三个字符串");
originator.saveState("第四个字符串");
originator.saveState("第五个字符串");
// 读取备忘录中对象的状态
Caretaker caretaker = new Caretaker(originator);
String state5 = caretaker.getState(4);
System.out.println(state5);
String state4 = caretaker.getState(3);
System.out.println(state4);
String state3 = caretaker.getState(2);
System.out.println(state3);
String state2 = caretaker.getState(1);
System.out.println(state2);
String state1 = caretaker.getState(0);
System.out.println(state1);
}
}运行以上代码,得到以下输出

五、总结
备忘录模式给我们提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态,在此同时,备忘录模式也实现了信息的封装,使得用户不需要关心状态的保存细节。
但是,备忘录模式的可扩展性并不是很好,每一种对象都需要对应一种备忘录,这将会导致类的数量膨胀,对内存无疑是一种考验。
到此这篇关于Java设计模式之备忘录模式的文章就介绍到这了,更多相关Java备忘录模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
