定义

备忘录模式是对象的行为型模式,备忘录对象是一个用来存储另外一个对象内部状态的快照的对象,备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化存储起来,从而可以使得在将来合适的时候把这个对象还原到存储起来的状态

意图

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态

主要解决问题

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态

何时使用

很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃

优缺点

优点:

  • 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这个时候使用备忘录模式,可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以保持封装的边界
  • 当发起人角色的状态改变时,有可能这个状态无效,这个时候就可以使用暂时存储起来的备忘录将状态复原

缺点:

消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存

结构



涉及的角色:

  • 备忘录(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设计模式:备忘录模式的更多相关文章

  1. JAVA 设计模式 备忘录模式

    用途 备忘录模式 (Memento) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 备忘录模式是一种行为型模式. 结构

  2. java设计模式---备忘录模式

    一.引子 俗话说:世上难买后悔药.所以凡事讲究个"三思而后行",但总常见有人做"痛心疾首"状:当初我要是--.如果真的有<大话西游>中能时光倒流的& ...

  3. Java设计模式-备忘录模式(Memento)

    主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C ...

  4. Java设计模式—备忘录模式

    个人感觉备忘录模式是一个比较难的设计模式,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法. 定义如下:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以 ...

  5. Java设计模式——组合模式

    JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...

  6. java设计模式--单列模式

    java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...

  7. 3.java设计模式-建造者模式

    Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...

  8. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  9. Java设计模式——外观模式

    JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构

随机推荐

  1. 2021-2-22:请你说下 CAP 理论并举例

    CAP CAP 理论是分布式系统中的一个老生常谈的理论了,最早由 Eric Brewer 在一个讲座中提出.在这个讲座中,在传统 ACID 理论以及当时比较流行但是比较抽象的的设计指导理论 BASE ...

  2. [Python学习笔记]正则表达式总结

    常用缩写字符及其含义表格查询 缩写字符分类 含义 \d 0-9的任意数字 \D 除0-9的数字以外的任何字符 \w 任何字母.数字或下划线字符(可以认为是匹配"单词"字符) \W ...

  3. 微信小程序:上滑触底加载下一页

    给商品列表页面添加一个上滑触底加载下一页的效果,滚动条触底之后就发送一个请求,来加载下一页数据, 先在getGoodsList中获取总条数 由于总页数需要再另外的一个方法中使用,所以要把总页数变成一个 ...

  4. Django-1.11中文文档-模型Models(一)

    官方文档链接 模型是数据信息的唯一并明确的来源.它包含了我们储存的数据的基本字段和行为.通常,每个模型映射到一张数据库表. 基本概念: 每个模型都是django.db.models.Model的一个子 ...

  5. SpineRuntime-Presentation - 基于 spine-libgdx 实现在 AndroidPresentation 上展示 Spine 动画

    SpineRuntime-Presentation 基于 spine-libgdx 实现在 AndroidPresentation 上展示 Spine 动画 Github地址 效果 可以在 Andro ...

  6. JavaScript初级学习

    1. JavaScript的介绍 前身是LiveScript+JavaScript JavaScript(js)是一个脚本语言 基于浏览器的脚本语言 基于对象,面向对象的一个编程语言 2. EcmaS ...

  7. 【MaixPy3文档】写好 Python 代码!

    本文是给有一点 Python 基础但还想进一步深入的同学,有经验的开发者建议跳过. 前言 上文讲述了如何认识开源项目和一些编程方法的介绍,这节主要来说说 Python 代码怎么写的一些演化过程和可以如 ...

  8. 使用SQLSERVER 2008 R2 配置邮件客户端发送DB数据流程要领

    设置邮件 QQ邮箱貌似不太行,建议用企业邮箱或者其他邮箱作为发件箱 新建一个邮件发件箱账号,具体邮件服务器按照各自邮件配置,是否使用ssl,自便 下一步,下一步,配置成功 use msdb Go DE ...

  9. Sentinel熔断降级

    sentinel流量控制 Sentinel流量控制&服务熔断降级介绍 流量控制介绍 在这里我用景区的例子解释一下 一个旅游景点日接待游客数量为8K,8K以后的游客就无法买票进去景区. 对应编程 ...

  10. DES加密--不安全加密

    package test; import java.security.InvalidKeyException; import java.security.Key; import java.securi ...