观世音甘泉活树的故事竟然是Java设计模式:备忘录模式
定义
备忘录模式是对象的行为型模式,备忘录对象是一个用来存储另外一个对象内部状态的快照的对象,备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化存储起来,从而可以使得在将来合适的时候把这个对象还原到存储起来的状态
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
主要解决问题
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态
何时使用
很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃
优缺点
优点:
- 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这个时候使用备忘录模式,可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以保持封装的边界
- 当发起人角色的状态改变时,有可能这个状态无效,这个时候就可以使用暂时存储起来的备忘录将状态复原
缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存
结构

涉及的角色:
备忘录(Memento)角色:
- 将发起人(Originator)对象的内部状态存储起来;备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态
- 备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取,备忘录有两个等效的接口:
- 窄接口:负责人(Caretaker)对象和其他除发起人对象之外的任何对象,看到的是备忘录的窄接口,这个接口只允许它把备忘录对象传给其他的对象
- 宽接口:发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复发起人对象的内部状态
发起人(Originator)角色:
- 创建一个含有当前的内部状态的备忘录对象
- 使用备忘录对象存储其内部状态
负责人(Caretaker)角色:
- 负责保存备忘录对象
- 不检查备忘录对象的内容
白箱实现
将发起人角色的状态存储在一个大家都看的到的地方,因此是破坏封装性的

源码如下:
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 this.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 this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
}
}
public class Caretaker {
private Memento memento;
/** 备忘录的取值方法 */
public Memento getMemento() {
return this.memento;
}
/** 备忘录的赋值方法 */
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
//改变发起人对象的状态
originator.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
caretaker.setMemento(originator.createMemento());
//修改发起人对象的状态
originator.setState("Off");
originator.restoreMemento(caretaker.getMemento());
//恢复发起人对象的状态
System.out.println("恢复状态:" + originator.getState());
}
}
黑箱实现
将Memento类设成Originator类的内部类,在外部提供一个标识接口MementoIF给Caretaker类以及其他对象

源码如下:
public class Originator {
private String state;
public Originator() {
}
/** 返回一个新的备忘录对象 */
public MementoIF createMemento() {
return new Memento(this.state);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(MementoIF memento) {
Memento memento1 = (Memento) memento;
this.state = memento1.getState();
}
/** 状态的取值方法 */
public String getState() {
return this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + this.state);
}
/** 内部成员类,备忘录 */
protected class Memento implements MementoIF {
private String saveState;
private Memento(String state) {
this.saveState = state;
}
/** 状态的取值方法 */
private String getState() {
return this.saveState;
}
/** 状态的赋值方法 */
private void setState(String state) {
this.saveState = state;
}
}
}
public interface MementoIF {
}
public class Caretaker {
private MementoIF memento;
/** 备忘录的取值方法 */
public MementoIF getMemento() {
return this.memento;
}
/** 备忘录的赋值方法 */
public void setMemento(MementoIF memento) {
this.memento = memento;
}
}
public class Client {
private static Originator o = new Originator();
private static Caretaker c = new Caretaker();
public static void main(String[] args) {
//改变发起人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
c.setMemento(o.createMemento());
//修改发起人对象的状态
o.setState("Off");
o.restoreMemento(c.getMemento());
//恢复发起人对象的状态
System.out.println("恢复状态:" + o.getState());
}
}
多重检查点
存储多个状态,或者叫做有多个检查点
public class Originator {
private Vector states;
private int index;
public Originator() {
this.states = new Vector();
this.index = 0;
}
/** 返回一个新的备忘录对象 */
public Memento createMemento() {
return new Memento(states, index);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(Memento memento) {
this.states = memento.getStates();
this.index = memento.getIndex();
}
/** 状态的赋值方法 */
public void setState(String state) {
this.states.addElement(state);
index++;
}
/** 打印出所有的状态 */
public void printStates() {
System.out.println("总的状态数量:" + index);
for (Enumeration e = states.elements(); e.hasMoreElements();) {
System.out.println(e.nextElement());
}
}
}
public class Memento {
private Vector states;
private int index;
public Memento(Vector states, int index) {
this.states = (Vector) states.clone();
this.index = index;
}
/** 状态的取值方法 */
public Vector getStates() {
return states;
}
/** 检查点指数的取值方法 */
public int getIndex() {
return index;
}
}
public class Caretaker {
private Originator originator;
private Vector vector = new Vector();
private int current;
public Caretaker(Originator originator) {
this.originator = originator;
this.current = 0;
}
/** 创建一个新的检查点 */
public int createMemento() {
Memento memento = originator.createMemento();
vector.addElement(memento);
return current++;
}
/** 将发起人恢复到某个检查点 */
public void restoreMemento(int index) {
Memento memento = (Memento) vector.elementAt(index);
originator.restoreMemento(memento);
}
/** 将某个检查点删除 */
public void removeMemento(int index) {
vector.removeElementAt(index);
}
}
public class Client {
private static Originator o = new Originator();
private static Caretaker c = new Caretaker(o);
public static void main(String[] args) {
//改变状态
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();
//恢复到第1个检查点
System.out.println("恢复到第1个检查点");
c.restoreMemento(1);
o.printStates();
//恢复到第3个检查点
System.out.println("恢复到第2个检查点");
c.restoreMemento(2);
o.printStates();
}
}

观世音甘泉活树的故事
孙大圣保护唐僧西行,路过万寿山五庄观,与道童发生口角,一时发怒,把人参果树推倒;大圣只好请观世音菩萨救活人参果树
在这里,果树的状态保存在观世音的甘露之中,菩萨可以从甘露中把果树的状态恢复过来,果树是发起人角色,甘露是备忘录角色,菩萨是负责人角色
public class SweetSpringWater {
private String fruiterState;
public SweetSpringWater(String fruiterState) {
this.fruiterState = fruiterState;
}
/** 获取果树的状态 */
public String getFruiterState() {
return fruiterState;
}
/** 设置果树的状态 */
public void setFruiterState(String fruiterState) {
this.fruiterState = fruiterState;
}
}
public class Fruiter {
private String fruiterState;
/** 返回一个新的备忘录对象 */
public SweetSpringWater createMemento() {
return new SweetSpringWater(fruiterState);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreSweetSpringWater(SweetSpringWater springWater) {
this.fruiterState = springWater.getFruiterState();
}
/** 果树状态的取值方法 */
public String getState() {
return this.fruiterState;
}
/** 果树状态态的赋值方法 */
public void setState(String fruiterState) {
this.fruiterState = fruiterState;
System.out.println("当前果树状态:" + this.fruiterState);
}
}
public class Goddess {
private SweetSpringWater sweetSpringWater;
/** 备忘录的取值方法 */
public SweetSpringWater getSweetSpringWater() {
return this.sweetSpringWater;
}
/** 备忘录的赋值方法 */
public void setMemento(SweetSpringWater sweetSpringWater) {
this.sweetSpringWater = sweetSpringWater;
}
}
public class Client {
public static void main(String[] args) {
Fruiter f = new Fruiter();
Goddess g = new Goddess();
//改变发起人对象的状态
f.setState("果树被孙悟空推倒了");
//创建备忘录对象,并将发起人对象的状态存储起来
g.setMemento(f.createMemento());
//修改发起人对象的状态
f.setState("观世音用甘泉恢复果树状态");
//恢复发起人对象的状态
System.out.println("恢复状态:" + f.getState());
}
}

观世音甘泉活树的故事竟然是Java设计模式:备忘录模式的更多相关文章
- JAVA 设计模式 备忘录模式
用途 备忘录模式 (Memento) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 备忘录模式是一种行为型模式. 结构
- java设计模式---备忘录模式
一.引子 俗话说:世上难买后悔药.所以凡事讲究个"三思而后行",但总常见有人做"痛心疾首"状:当初我要是--.如果真的有<大话西游>中能时光倒流的& ...
- Java设计模式-备忘录模式(Memento)
主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C ...
- Java设计模式—备忘录模式
个人感觉备忘录模式是一个比较难的设计模式,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法. 定义如下:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以 ...
- Java设计模式——组合模式
JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...
- java设计模式--单列模式
java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...
- 3.java设计模式-建造者模式
Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- Java设计模式——外观模式
JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构
随机推荐
- 2021-2-22:请你说下 CAP 理论并举例
CAP CAP 理论是分布式系统中的一个老生常谈的理论了,最早由 Eric Brewer 在一个讲座中提出.在这个讲座中,在传统 ACID 理论以及当时比较流行但是比较抽象的的设计指导理论 BASE ...
- [Python学习笔记]正则表达式总结
常用缩写字符及其含义表格查询 缩写字符分类 含义 \d 0-9的任意数字 \D 除0-9的数字以外的任何字符 \w 任何字母.数字或下划线字符(可以认为是匹配"单词"字符) \W ...
- 微信小程序:上滑触底加载下一页
给商品列表页面添加一个上滑触底加载下一页的效果,滚动条触底之后就发送一个请求,来加载下一页数据, 先在getGoodsList中获取总条数 由于总页数需要再另外的一个方法中使用,所以要把总页数变成一个 ...
- Django-1.11中文文档-模型Models(一)
官方文档链接 模型是数据信息的唯一并明确的来源.它包含了我们储存的数据的基本字段和行为.通常,每个模型映射到一张数据库表. 基本概念: 每个模型都是django.db.models.Model的一个子 ...
- SpineRuntime-Presentation - 基于 spine-libgdx 实现在 AndroidPresentation 上展示 Spine 动画
SpineRuntime-Presentation 基于 spine-libgdx 实现在 AndroidPresentation 上展示 Spine 动画 Github地址 效果 可以在 Andro ...
- JavaScript初级学习
1. JavaScript的介绍 前身是LiveScript+JavaScript JavaScript(js)是一个脚本语言 基于浏览器的脚本语言 基于对象,面向对象的一个编程语言 2. EcmaS ...
- 【MaixPy3文档】写好 Python 代码!
本文是给有一点 Python 基础但还想进一步深入的同学,有经验的开发者建议跳过. 前言 上文讲述了如何认识开源项目和一些编程方法的介绍,这节主要来说说 Python 代码怎么写的一些演化过程和可以如 ...
- 使用SQLSERVER 2008 R2 配置邮件客户端发送DB数据流程要领
设置邮件 QQ邮箱貌似不太行,建议用企业邮箱或者其他邮箱作为发件箱 新建一个邮件发件箱账号,具体邮件服务器按照各自邮件配置,是否使用ssl,自便 下一步,下一步,配置成功 use msdb Go DE ...
- Sentinel熔断降级
sentinel流量控制 Sentinel流量控制&服务熔断降级介绍 流量控制介绍 在这里我用景区的例子解释一下 一个旅游景点日接待游客数量为8K,8K以后的游客就无法买票进去景区. 对应编程 ...
- DES加密--不安全加密
package test; import java.security.InvalidKeyException; import java.security.Key; import java.securi ...