设计模式《JAVA与模式》之备忘录模式
在阎宏博士的《JAVA与模式》一书中开头是这样描述备忘录(Memento)模式的:
备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。
备忘录模式的结构
备忘录模式的结构图如下所示
备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。
备忘录(Memento)角色
备忘录角色又如下责任:
(1)将发起人(Originator)对象的内战状态存储起来。备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态。
(2)备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取。
备忘录有两个等效的接口:
● 窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄接口(narrow interface),这个窄接口只允许它把备忘录对象传给其他的对象。
● 宽接口:与负责人对象看到的窄接口相反的是,发起人对象可以看到一个宽接口(wide interface),这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态。
发起人(Originator)角色
发起人角色有如下责任:
(1)创建一个含有当前的内部状态的备忘录对象。
(2)使用备忘录对象存储其内部状态。
负责人(Caretaker)角色
负责人角色有如下责任:
(1)负责保存备忘录对象。
(2)不检查备忘录对象的内容。
“白箱”备忘录模式的实现
备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。因此这个实现又叫做“白箱实现”。
“白箱”实现将发起人角色的状态存储在一个大家都看得到的地方,因此是破坏封装性的。但是通过程序员自律,同样可以在一定程度上实现模式的大部分用意。因此白箱实现仍然是有意义的。
下面给出一个示意性的“白箱实现”。
源代码
发起人角色类,发起人角色利用一个新创建的备忘录对象将自己的内部状态存储起来。
public class Originator { private String state;
/**
* 工厂方法,返回一个新的备忘录对象
*/
public Memento createMemento(){
return new Memento(state);
}
/**
* 将发起人恢复到备忘录对象所记载的状态
*/
public void restoreMemento(Memento memento){
this.state = memento.getState();
} public String getState() {
return state;
} public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + this.state);
} }
备忘录角色类,备忘录对象将发起人对象传入的状态存储起来。
public class Memento { private String state; public Memento(String state){
this.state = state;
} public String getState() {
return state;
} public void setState(String state) {
this.state = state;
} }
负责人角色类,负责人角色负责保存备忘录对象,但是从不修改(甚至不查看)备忘录对象的内容。
public class Caretaker { private Memento memento;
/**
* 备忘录的取值方法
*/
public Memento retrieveMemento(){
return this.memento;
}
/**
* 备忘录的赋值方法
*/
public void saveMemento(Memento memento){
this.memento = memento;
}
}
客户端角色类
public class Client { public static void main(String[] args) { Originator o = new Originator();
Caretaker c = new Caretaker();
//改变负责人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态储存起来
c.saveMemento(o.createMemento());
//修改发起人的状态
o.setState("Off");
//恢复发起人对象的状态
o.restoreMemento(c.retrieveMemento()); System.out.println(o.getState());
} }
在上面的这个示意性的客户端角色里面,首先将发起人对象的状态设置成“On”,并创建一个备忘录对象将这个状态存储起来;然后将发起人对象的状态改成“Off”;最后又将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态。
系统的时序图更能够反映出系统各个角色被调用的时间顺序。如下图是将发起人对象的状态存储到白箱备忘录对象中去的时序图。
可以看出系统运行的时序是这样的:
(1)将发起人对象的状态设置成“On”。
(2)调用发起人角色的createMemento()方法,创建一个备忘录对象将这个状态存储起来。
(3)将备忘录对象存储到负责人对象中去。
将发起人对象恢复到备忘录对象所记录的状态的时序图如下所示:
可以看出,将发起人对象恢复到备忘录对象所记录的状态时,系统的运行时序是这样的:
(1)将发起人状态设置成“Off”。
(2)将备忘录对象从负责人对象中取出。
(3)将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态。
“黑箱”备忘录模式的实现
备忘录角色对发起人(Originator)角色对象提供一个宽接口,而为其他对象提供一个窄接口。这样的实现叫做“黑箱实现”。
在JAVA语言中,实现双重接口的办法就是将备忘录角色类设计成发起人角色类的内部成员类。
将Memento设成Originator类的内部类,从而将Memento对象封装在Originator里面;在外部提供一个标识接口MementoIF给Caretaker以及其他对象。这样,Originator类看到的是Menmento的所有接口,而Caretaker以及其他对象看到的仅仅是标识接口MementoIF所暴露出来的接口。
使用内部类实现备忘录模式的类图如下所示。
源代码
发起人角色类Originator中定义了一个内部的Memento类。由于此Memento类的全部接口都是私有的,因此只有它自己和发起人类可以调用。
package memento.sample2; /**
* @author chen_dz
* @date :2012-6-2 上午10:11:08
*/
public class Originator { private String state; public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
System.out.println("赋值状态:" + state);
}
/**
* 工厂方法,返还一个新的备忘录对象
*/
public MementoIF createMemento(){
return new Memento(state);
}
/**
* 发起人恢复到备忘录对象记录的状态
*/
public void restoreMemento(MementoIF memento){
this.setState(((Memento)memento).getState());
} private class Memento implements MementoIF{ private String state;
/**
* 构造方法
*/
private Memento(String state){
this.state = state;
} private String getState() {
return state;
}
private void setState(String state) {
this.state = state;
}
}
}
窄接口MementoIF,这是一个标识接口,因此它没有定义出任何的方法。
public interface MementoIF { }
负责人角色类Caretaker能够得到的备忘录对象是以MementoIF为接口的,由于这个接口仅仅是一个标识接口,因此负责人角色不可能改变这个备忘录对象的内容。
public class Caretaker { private MementoIF memento;
/**
* 备忘录取值方法
*/
public MementoIF retrieveMemento(){
return memento;
}
/**
* 备忘录赋值方法
*/
public void saveMemento(MementoIF memento){
this.memento = memento;
}
}
客户端角色类
public class Client { public static void main(String[] args) {
Originator o = new Originator();
Caretaker c = new Caretaker();
//改变负责人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
c.saveMemento(o.createMemento());
//修改发起人对象的状态
o.setState("Off");
//恢复发起人对象的状态
o.restoreMemento(c.retrieveMemento());
} }
客户端首先
(1)将发起人对象的状态设置为“On”。
(2)调用createMemento()方法,创建一个备忘录对象将这个状态存储起来(此时createMemento()方法还回的明显类型是MementoIF接口,真实类型为Originator内部的Memento对象)。
(3)将备忘录对象存储到负责人对象中去。由于负责人对象拿到的仅是MementoIF接口,因此无法读出备忘录对象内部的状态。
(4)将发起人对象的状态设置为“Off”。
(5)调用负责人对象的retrieveMemento()方法将备忘录对象取出。注意此时仅能得到MementoIF接口,因此无法读出此对象的内部状态。
(6)调用发起人对象的restoreMemento()方法将发起人对象的状态恢复成备忘录对象所存储的起来的状态,即“On”状态。由于发起人对象的内部类Memento实现了MementoIF接口,这个内部类是传入的备忘录对象的真实类型,因此发起人对象可以利用内部类Memento的私有接口读出此对象的内部状态。
多重检查点
前面所给出的白箱和黑箱的示意性实现都是只存储一个状态的简单实现,也可以叫做只有一个检查点。常见的系统往往需要存储不止一个状态,而是需要存储多个状态,或者叫做有多个检查点。
备忘录模式可以将发起人对象的状态存储到备忘录对象里面,备忘录模式可以将发起人对象恢复到备忘录对象所存储的某一个检查点上。下面给出一个示意性的、有多重检查点的备忘录模式的实现。
源代码
发起人角色源代码
public class Originator { private List<String> states;
//检查点指数
private int index;
/**
* 构造函数
*/
public Originator(){
states = new ArrayList<String>();
index = 0;
}
/**
* 工厂方法,返还一个新的备忘录对象
*/
public Memento createMemento(){
return new Memento(states , index);
}
/**
* 将发起人恢复到备忘录对象记录的状态上
*/
public void restoreMemento(Memento memento){
states = memento.getStates();
index = memento.getIndex();
}
/**
* 状态的赋值方法
*/
public void setState(String state){
states.add(state);
index++;
}
/**
* 辅助方法,打印所有状态
*/
public void printStates(){ for(String state : states){
System.out.println(state);
}
}
}
备忘录角色类,这个实现可以存储任意多的状态,外界可以使用检查点指数index来取出检查点上的状态。
public class Memento { private List<String> states;
private int index;
/**
* 构造函数
*/
public Memento(List<String> states , int index){
this.states = new ArrayList<String>(states);
this.index = index;
}
public List<String> getStates() {
return states;
}
public int getIndex() {
return index;
} }
负责人角色类
public class Caretaker { private Originator o;
private List<Memento> mementos = new ArrayList<Memento>();
private int current;
/**
* 构造函数
*/
public Caretaker(Originator o){
this.o = o;
current = 0;
}
/**
* 创建一个新的检查点
*/
public int createMemento(){
Memento memento = o.createMemento();
mementos.add(memento);
return current++;
}
/**
* 将发起人恢复到某个检查点
*/
public void restoreMemento(int index){
Memento memento = mementos.get(index);
o.restoreMemento(memento);
}
/**
* 将某个检查点删除
*/
public void removeMemento(int index){
mementos.remove(index);
}
}
客户端角色源代码
public class Client { public static void main(String[] args) { Originator o = new Originator();
Caretaker c = new Caretaker(o);
//改变状态
o.setState("state 0");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 1");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 2");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 3");
//建立一个检查点
c.createMemento();
//打印出所有检查点
o.printStates();
System.out.println("-----------------恢复检查点-----------------");
//恢复到第二个检查点
c.restoreMemento(2);
//打印出所有检查点
o.printStates();
} }
运行结果如下:
aaarticlea/png;base64,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" alt="" />
可以看出,客户端角色通过不断改变发起人角色的状态,并将之存储在备忘录里面。通过指明检查点指数可以将发起人角色恢复到相应的检查点所对应的状态上。
将发起人的状态存储到备忘录对象中的活动序列图如下:
系统运行的时序是这样的:
(1)将发起人对象的状态设置成某个有效状态;
(2)调用负责人角色的createMemento()方法,负责人角色会负责调用发起人角色和备忘录角色,将发起人对象的状态存储起来。
将发起人对象恢复到某一个备忘录对象的检查点的活动序列图如下:
由于负责人角色的功能被增强了,因此将发起人对象恢复到备忘录对象所记录的状态时,系统运行的时序被简化了:
(1)调用负责人角色的restoreMemento()方法,将发起人恢复到某个检查点。
“自述历史”模式
所谓“自述历史”模式(History-On-Self Pattern)实际上就是备忘录模式的一个变种。在备忘录模式中,发起人(Originator)角色、负责人(Caretaker)角色和备忘录(Memento)角色都是独立的角色。虽然在实现上备忘录类可以成为发起人类的内部成员类,但是备忘录类仍然保持作为一个角色的独立意义。在“自述历史”模式里面,发起人角色自己兼任负责人角色。
“自述历史”模式的类图如下所示:
备忘录角色有如下责任:
(1)将发起人(Originator)对象的内部状态存储起来。
(2)备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取。
发起人角色有如下责任:
(1)创建一个含有它当前的内部状态的备忘录对象。
(2)使用备忘录对象存储其内部状态。
客户端角色有负责保存备忘录对象的责任。
源代码
窄接口MementoIF,这是一个标识接口,因此它没有定义出任何的方法。
public interface MementoIF { }
发起人角色同时还兼任负责人角色,也就是说它自己负责保持自己的备忘录对象。
public class Originator { public String state;
/**
* 改变状态
*/
public void changeState(String state){
this.state = state;
System.out.println("状态改变为:" + state);
}
/**
* 工厂方法,返还一个新的备忘录对象
*/
public Memento createMemento(){
return new Memento(this);
}
/**
* 将发起人恢复到备忘录对象所记录的状态上
*/
public void restoreMemento(MementoIF memento){
Memento m = (Memento)memento;
changeState(m.state);
} private class Memento implements MementoIF{ private String state;
/**
* 构造方法
*/
private Memento(Originator o){
this.state = o.state;
}
private String getState() {
return state;
} }
}
客户端角色类
public class Client { public static void main(String[] args) {
Originator o = new Originator();
//修改状态
o.changeState("state 0");
//创建备忘录
MementoIF memento = o.createMemento();
//修改状态
o.changeState("state 1");
//按照备忘录恢复对象的状态
o.restoreMemento(memento);
} }
由于“自述历史”作为一个备忘录模式的特殊实现形式非常简单易懂,它可能是备忘录模式最为流行的实现形式。
设计模式《JAVA与模式》之备忘录模式的更多相关文章
- 设计模式之第17章-备忘录模式(Java实现)
设计模式之第17章-备忘录模式(Java实现) 好男人就是我,我就是曾小贤.最近陈赫和张子萱事件闹得那是一个沸沸扬扬.想想曾经每年都有爱情公寓陪伴的我现如今过年没有了爱情公寓总是感觉缺少点什么.不知道 ...
- C#设计模式学习笔记:(22)备忘录模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8176974.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第十个模式--备 ...
- Java设计模式(21)——行为模式之备忘录模式(Memento)
一.概述 概念 UML简图 角色 根据下图得到角色 备忘录角色(Memento).发起人角色(Originator).负责人角色(Caretaker) 二.实践 使用白箱实现,给出角色的代码: 发起人 ...
- 我所理解的设计模式(C++实现)——备忘录模式(Memento Pattern)
概述: 我们玩单机游戏的时候总会遇到老婆大人的各位事情,一会去买瓶醋了,一会去打个酱油了,会耽误我们玩游戏的进程,但是此时我们能有“保存游戏”这个宝贝,我们的主基地不会在我们打酱油的时候被对手拆掉. ...
- 设计模式20---设计模式之备忘录模式(Memento)(行为型)
1.讲解备忘录模式 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Token模式,是GoF的23种设计模式之一,属于行为模式. 1.1定义 在不破坏封 ...
- C#设计模式之二十二备忘录模式(Memeto Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第十个模式,该模式是[备忘录模式],英文名称是:Memento Pattern.按老规矩,先从名称上来看看这个模式,个人的最初理解就 ...
- C#设计模式之二十二备忘录模式(Memento Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第十个模式,该模式是[备忘录模式],英文名称是:Memento Pattern.按老规矩,先从名称上来看看这个模式,个人的最初理解就是对某个对象的状态进行保 ...
- 《Android源码设计模式》--状态模式--责任链模式--解释器模式--命令模式--观察者模式--备忘录模式--迭代器模式
[状态模式] No1: Wifi设置界面是一个叫做WifiSetting的Fragment实现的 No2: 在不同的状态下对于扫描Wifi这个请求的处理是完全不一样的.在初始状态下扫描请求被直接忽略, ...
- 【设计模式】行为型07备忘录模式(Memento Pattern)
参考地址:http://www.runoob.com/design-pattern/memento-pattern.html 对原文总结调整,以及修改代码以更清晰的展示: 备忘录模式(快照模式): ...
- Head First设计模式——中介者模式和备忘录模式
中介者 中介者模式:使用中介者来集中相关对象之间复杂的沟通方式和控制方式. Bob有一个自动屋,当他的闹钟响了只有,闹钟会告诉咖啡壶开始煮咖啡.后来客户不断的提出许多新需求:周末不要提供咖啡.下班后需 ...
随机推荐
- 2018.11.02 NOIP模拟 飞越行星带(最小生成树/二分+并查集)
传送门 发现题目要求的就是从下到上的瓶颈路. 画个图出来发现跟去年noipnoipnoip提高组的奶酪差不多. 于是可以二分宽度+并查集检验,或者直接求瓶颈. 代码
- nginx location配置和rewrite写法
location = / { # 精确匹配 / ,主机名后面不能带任何字符串 [ configuration A ] } location / { # 因为所有的地址都以 / 开头,所以这条规则将匹配 ...
- 泡泡机器人SLAM 2019
LDSO:具有回环检测的直接稀疏里程计:LDSO:Direct Sparse Odometry with Loop Closure Abstract—In this paper we present ...
- Set tooltip on customized tab header in WPF
<UserControl> <UserControl.Resources> <ResourceDictionary> <ResourceDictionary. ...
- Qt_模块简介
Qt4 和 Qt5最大的区别之一就是底层架构有了修改.Qt5引入了模块化的概念,讲众多功能细分到几个模块之中.需要达到,用什么模块知道到哪个模块去寻找. Qt5模块分为Essentials Modul ...
- 类中main函数的快捷创建
方法一: 新建类时,选择创建 方法二: 打出main-->Alt + /
- 差值的再议-Hermite差值
1. 插值法 插值法又称“内插法”,是利用函数f (x)在某区间中已知的若干点的函数值,作出适当的特定函数,在区间的其他点上用这特定函数的值作为函数f (x)的近似值,这种方法称为插值法. 如果这特定 ...
- 1、从C语言到C++
1.面向对象的C++ c++是在C语言的基础上发展起来的一门语言,C++是即支持结构化程序编程又支持面向对象程序设计的混合型语言.他一方面提供了对C的兼容性,保持了C的简介.高效,接近汇编语言的特点, ...
- 4、C语言的编译过程链
在学校学C语言的时候,很多人都不是很注重编译过程链,但是其实编译过程是项目过程中很重要的一部分,有时候有些语法诸如static.volatile等关键词不理解时大多数都是对整个C语言编译链没有进行过详 ...
- 数据统计--union all 执行多条sql
需求--统计hive某张表type字段不同取值的数据量 我们已知某张表的type的取值是1,2,3,4,5,想要统计不同type的数据量,并清晰的展现出来.可以通过union all 的方式,sql如 ...