其目的是,在不违反封装原则的前提下.採集和备份一个对象的内部状态以便这个对象能够在以后恢复到之前的某个状态.

在Memento模式中,有例如以下角色:
1.Memento (备忘录)
* 存储Originator的内部状态. 依据Originator的须要.能够存储随意的内部状态.
* 保护对状态的訪问.除了Originator对象外,其它对象不能訪问其存储的内部状态.Memeoto实际上提供了2个接口.
Caretaker仅仅能訪问Memento的窄接口(narrow interface) - 它仅仅能够把memento传递给其它对象.
相反,Originator能够訪问Memento的宽接口(wide interface). 通过这个接口,能够让Originator获取足够的信息以恢复到之前的状态.理想情况下,仅仅有创建memento的Originator才有权限訪问memento的内部状态信息.
2.Originator (发起人)
* 能够创建一个新的memento, 并把自己的当前状态信息存储到memento里面
* 能够使用memento来恢复其内部状态信息
3.Caretaker (负责人)
* 负责维护和管理memento对象
* 从不正确memento的内容进行操作或者測试

备忘录模式的操作过程 
1、client为发起人角色创建一个备忘录对象。

 
2、调用发起人对象的某个操作。这个操作是能够撤销的。

 
3、检查发起人对象所出状态的有效性。检查的方式能够是发起人对象的内部自查。也能够由某个外部对象进行检查。 
4、假设须要的话。将发起人的操作撤销。也就是说依据备忘录对象的记录。将发起人对象的状态恢复过来。 

“假如”协议模式的操作过程: 
1、将发起人对象做一个拷贝。

 
2、在拷贝上运行某个操作。

 
3、检查这个拷贝的状态是否有效和自恰。 
4、假设检查结果是无效或者不自恰的,那么扔掉这个拷贝,并触发异常处理程序。相反。假设检查是有效和自恰的,那么在原对象上运行这个操作 
显然这一做法对于撤销一个操作并恢复操作前状态较为复杂和困难的发起人对象来说是一个较为慎重和有效的做法。 

“假如”协议模式的长处和缺点 
详细来说,这个做法的好处是能够保证发起人对象永远不会处于无效或不自恰的状态上。这样作的短处是成功的操作必须运行两次。 
假设操作的成功率较低的话。这样做就比較划算。反之就不太划算。

 

使用备忘录模式的长处和缺点 
一、备忘录模式的长处 
1、有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,可是必须要由发起人对象自己读取,这时, 
   使用备忘录模式能够把复杂的发起人内部信息对其它的对象屏蔽起来。从而能够恰当地保持封装的边界。 
2、本模式简化了发起人类。发起人不再须要管理和保存其内部状态的一个个版本号,client能够自行管理他们所需 
   要的这些状态的版本号。

 
3、当发起人角色的状态改变的时候,有可能这个状态无效。这时候就能够使用临时存储起来的备忘录将状态复原。 
二、备忘录模式的缺点: 
1、假设发起人角色的状态须要完整地存储到备忘录对象中。那么在资源消耗上面备忘录对象会非常昂贵。

 
2、当负责人角色将一个备忘录 存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法 
   提醒用户一个操作是否非常昂贵。882——P  
3、当发起人角色的状态改变的时候,有可能这个协议无效。

假设状态改变的成功率不高的话,不如採取“假如”协议模式。

(1)宽接口和白箱:
public class Client {

   private static Originator originator = new Originator();

   private static Caretaker c = new Caretaker();

   public static void main(String[] args) {

      // 该发起人对象的状态

      originator.setState("On");

      // 创建备忘录对象,并将发起人对象的状态存储起来

      c.saveMemento(originator.createMemento());

      // 改动发起人对象的状态

      originator.setState("Off");

      // 恢复发起人对象的状态

      originator.restoreMemento(c.retrieveMemento());

   }

}

// 发起人角色

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("Current state = " + this.state);

   }

}
/*

 * 备忘录模式要求备忘录对象提供两个不同的接口:一个宽接口提供给发起人对象,还有一个窄接口提供给全部其它的对象,包含负责人对象。

* 宽接口同意发起人读取到全部的数据。窄接口仅仅同意它把备忘录对象传给其它的对象而看不到内部的数据。

 */

// 备忘录角色

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;

   }

}

/*

 * 负责人角色负责保存备忘录对象,可是从不改动(甚至不查看)备忘录对象的内容(一个更好的实现是负责人对象根本无法从备忘录 对象中读取个改动其内容)

 */

// 负责人角色

class Caretaker {

   private Memento memento;

   // 备忘录的取值方法

   public Memento retrieveMemento() {

      return this.memento;

   }

   // 备忘录的赋值方法

   public void saveMemento(Memento memento) {

      this.memento = memento;

   }

}

首先将发起人对象的状态设置成“On”(或者不论什么有效状态),而且创建一个备忘录对象将这个状态存储起来。然后将发起人对象的状态改成“Off”(或者不论什么状态);最后又将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态(或者先前所存储的不论什么状态)
备忘录系统运行的时序是这种:
(1)将发起人对象的状态设置成“On”。
(2)调用发起人角色的createMemento()方法,创建一个备忘录对象将这个状态存储起来。
(3)将备忘录对象存储到负责人对象中去。
备忘录系统恢复的时序是这种:
(1)将发起人对象的状态设置成“Off”;
(2)将备忘录对象从负责人对象中取出;
(3)将发起人对象恢复到备忘录对象所存储起来的状态。“On”状态。
白箱实现的优缺点
白箱实现的一个明显的好处是比較简单,因此经常常使用做教学目的。

白箱实现的一个明显的缺点是破坏对发起人状态的封装。

(2)窄接口或者黑箱实现:

//client

public class Client {

   private static Originator originator = new Originator();

   private static Caretaker c = new Caretaker();

   public static void main(String[] args) {

      // 该发起人对象的状态

      originator.setState("On");

      // 创建备忘录对象。并将发起人对象的状态存储起来

      c.saveMemento(originator.createMemento());

      // 改动发起人对象的状态

      originator.setState("Off");

      // 恢复发起人对象的状态

      originator.restoreMemento(c.retrieveMemento());

   }

}
// 发起人角色

class Originator {

   private String state;

   public Originator() {

   }

   // 工厂方法,返还一个新的备忘录对象

   public MementoIF createMemento() {

      return new Memento(this.state);

   }

   // 将发起人恢复到备忘录对象记录的状态

   public void restoreMemento(MementoIF memento) {

      Memento aMemento = (Memento) memento;

      this.setState(aMemento.getState());

   }

   public String getState() {

      return this.state;

   }

   public void setState(String state) {

      this.state = state;

      System.out.println("state =" + state);

   }

   protected class Memento implements MementoIF {

      private String savedState;

      public Memento(String someState) {

        this.savedState = someState;

      }

      private void setState(String someState) {

        savedState = someState;

      }

      private String getState() {

        return savedState;

      }

   }

}

interface MementoIF {

}

// 备忘录角色

class Memento implements MementoIF {

   private String state;

   public Memento(String state) {

      this.state = state;

   }

   public String getState() {

      return this.state;

   }

   public void setState(String state) {

      this.state = state;

   }

}

class Caretaker {

   private MementoIF memento;

   public MementoIF retrieveMemento() {

      return this.memento;

   }

   public void saveMemento(MementoIF memento) {

      this.memento = memento;

   }

}	

黑箱实现运行时的时序为;
  (1)将发起人对象的状态设置成“On”。
(2)调用发起人角色的 createMemento()方法。创建一个备忘录对象将这个状态存储起来。

(3)将备忘录对象存储到负责人对象中去。因为负责人对象拿到的仅是 MementoIF类型,因此无法读出备忘录内部的状态。
恢复时的时序为:
(1)将发起人对象的状态设置成“Off”。
(2)将备忘录对象从负责人对象中取出。

注意此时仅能得到 MementoIF接口,因此无法读出此对象的内部状态
(3)将发起人对象的状态恢复成备忘录对象所存储起来的状态。,因为发起人对象的内部类Memento实现了MementoIF接口
这个内部类是传入的备忘录对象的真实类型,因此发起人对象能够利用内部类Memento 的私有 接口读出此对象的内部状态。

(3)存储多个状态的备忘录模式:

//发起人角色
import java.util.Vector;
import java.util.Enumeration; public class Originator{
private Vector states;
private int index; public Originator(){
states = new Vector();
index = 0;
} public Memento createMementor(){
return new Mementor(states,index);
} public void restoreMementor(Mementor memento){
states = memento.getStates();
index = memento.getIndex()。
} public void setState(String state){
this.states.addElement(state);
index ++;
} //辅助方法。打印出全部的状态
public void printStates(){
System.out.println("Total number of states: " + index);
for(Enumeration e = states.elements();e.hasMoreElements();){
system.out.println(e.nextElement());
}
}
}
//备忘录角色
import java.util.Vector; public class Memento{
private Vector states;
private int index;
//<span style="font-size: 14px; font-family: Arial, Helvetica, sans-serif;">备忘录的构造子克隆了传入的states,然后将克隆存入到备忘录对象内部,这是一个重要的细节,因为不这种话,将会</span><pre title="备忘录(Memento Pattern)模式 【行为模式第一篇】" style="font-size: 14px;"> //将会造成client和备忘录对象持有对同一个Vector对象的引用,也能够同一时候改动这个Vector对象,会造成系统崩溃。

public Memento(Vector states,int index){this.states = (Vector)states.clone();this.index = index;}//状态取值方法Vector getStates(){return states;}//检查点取值方法int getIndex(){return this.index;}}


//负责人角色
import java.util.Vector; public class Caretaker{
private Originator o;
private Vector mementos = new Vector();
private int current; public Caretaker(Originator o){
this.o = o;
current = 0;
} public int createMemento(){
Memento memento = o.createMemento();
mementos.addElement(memento);
return current ++;
} //将发起人恢复到某个检查点
public void restoreMemento(int index){
Memento memento = (Memento)mementos.elementAt(index);
o.restoreMemento(memento);
} //某个检查点删除
public void removeMemento(int index){
mementos.removeElementAt(index);
}
}

//client
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.setState("state 4"); c.createMemento(); o.printStates(); //恢复到第二个检查点
System.out.println("Restoring to 2"); c.restoreMemento(2); o.printStates(); System.out.println("Restoring to 0"); c.restoreMemento(0); o.printStates(); System.out.println("Restoring to 3"); c.restoreMemento(3); o.printStates(); }
}

(4)自述历史模式(备忘录模式的一个变种)
因为“自述历史”作为一个备忘录模式的特殊实现形式非常easy易懂。它可能是备忘录模式最为流行的实现形式。

 

//窄接口
public interface MementoIF{}

//发起人角色
public class Originator{
public String state; public Originator(){} public void changeState(String state){
this.state = state;
System.out.println("State has been changed to : " + state);
} public Memento createMemento(){
return new Memento(this);
} public void restoreMemento(MementoIF memento){
Memento m = (Memento)memento;
changeState(m.state);
} class Memento implements MementoIF{
private String state; private String getState(){
return state;
} private Memento(Originator o){
this.state = o.state;
}
}
}

//client
public class Client{
private static Originator o;
private static MementoIF memento; public static void main(String args[]){
o = new Originator();
o.changeState("State 1");
memento = o.createMemento();
o.changeState("State 2");
o.restoreMemento(memento);
}
}

七、备忘录模式Memento(行为型模式)的更多相关文章

  1. 设计模式20:Memento 备忘录模式(行为型模式)

    Memento 备忘录模式(行为型模式) 对象状态的回溯 对象状态的变化无端,如何回溯.恢复对象在某个点的状态? 动机(Motivation) 在软件构建过程中,某些对象的状态在转换过程中,可能由于某 ...

  2. 设计模式15:Interpreter 解释器模式(行为型模式)

    Interpreter 解释器模式(行为型模式) 动机(Motivation) 在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变 ...

  3. 设计模式17:Iterator 迭代器模式(行为型模式)

    Iterator 迭代器模式(行为型模式) 动机(Motivation) 在软件构建过程中,集合对象内部结构常常变化各异.但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码可以透 ...

  4. 设计模式16:Mediator 中介者模式(行为型模式)

    Mediator 中介者模式(行为型模式) 依赖关系的转化 动机(Motivation) 在软件构建过程中,经常出现多个对象互相关联交互的情况,对象之间经常会维持一种复杂的应用关系,如果遇到一些需求的 ...

  5. 设计模式23:Visitor 访问者模式(行为型模式)

    Visitor 访问者模式(行为型模式) 动机(Motivation)在软件构造过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的修改,将会给子类带来繁重的 ...

  6. 设计模式22:Strategy 策略模式(行为型模式)

    Strategy 策略模式(行为型模式) 动机(Motivation) 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂:而且有时候支持 ...

  7. 设计模式21:State 状态模式(行为型模式)

    State 状态模式(行为型模式) 动机(Motivation) 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态的行为就可能完全不同. ...

  8. 设计模式19:Chain Of Responsibility 职责链模式(行为型模式)

    Chain Of Responsibility 职责链模式(行为型模式) 请求的发送者与接受者 某些对象请求的接受者可能有多种多样,变化无常…… 动机(Motivation) 在软件构建过程中,一个请 ...

  9. 设计模式14:Command 命令模式(行为型模式)

    Command 命令模式(行为型模式) 耦合与变化 耦合是软件不能抵御变化的根本性原因.不仅实体对象与实体对象之间存在耦合关系,实体对象与行为操作之间也存在耦合关系. 动机(Motivation) 在 ...

  10. 设计模式13:Template Method 模板方法模式(行为型模式)

    Template Method 模板方法模式(行为型模式) 变与不变 变化——是软件永恒的主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何分析,并发现体系中的变化点和稳定点,并使用特 ...

随机推荐

  1. 【Android学习笔记】Mac下Android Studio开发环境搭建

    本文由@ray 出品,转载请注明出处.  文章链接:http://www.cnblogs.com/wolfray/p/7829069.html 对于移动端这块,笔者之前一直都是进行iOS开发的,也从来 ...

  2. Linux学习日记之crontab使用notify-send实现每小时通知提醒

    crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行 通过crontab -e 可以打开编辑文件添加新的命令 notif ...

  3. [转帖]关于flask-login中各种API使用实例

    原贴:http://www.cnblogs.com/alima/p/5796298.html 简介:简单的集成flask,WTForms,包括跨站请求伪造(CSRF),文件上传和验证码. 一.安装(I ...

  4. 联想 K5 Pro(L38041)免解锁BL 免rec 保留数据 ROOT Magisk Xposed 救砖 ZUI 5.0.188

    >>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...

  5. Verification Mind Games---how to think like a verifier像验证工程师一样思考

    1. 有效的验证需要验证工程师使用不同于设计者的思维方式思考问题.具体来说,验证更加关心在严格遵循协议的基础上发现设计里面的bug,搜索corner cases,对设计的不一致要保持零容忍的态度. m ...

  6. Angular——依赖注入

    基本介绍 1.AngularJS采用模块化的方式组织代码,将一些通用逻辑封装成一个对象或函数,实现最大程度的复用,这导致了使用者和被使用者之间存在依赖关系. 2.所谓依赖注入是指在运行时自动查找依赖关 ...

  7. Nuxt.js使用详解

    首先来讲一下服务端渲染 直白的说就是在服务端拿数据进行解析渲染,直接生成html片段返回给前端.具体用法也有很多种比如: 传统的服务端模板引擎渲染整个页面 服务渲染生成htmll代码块, 前端 AJA ...

  8. 关于fragment+viewpager的优化

    上次写了一个问答项目,用的fragment+viewpager架构,后来发现,划了几次之后,再划回来,会重新加载布局,重新获取数据,这样整个程序和卡,并且占用太多的网络资源. 当时的解决办法是,自己重 ...

  9. 搜索--P1219 N皇后

    题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...

  10. POJ3616 Milking Time【dp】

    Description Bessie is such a hard-working cow. In fact, she is so focused on maximizing her producti ...