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

在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. Python之pandas数据加载、存储

    Python之pandas数据加载.存储 0. 输入与输出大致可分为三类: 0.1 读取文本文件和其他更好效的磁盘存储格式 2.2 使用数据库中的数据 0.3 利用Web API操作网络资源 1. 读 ...

  2. 5步上手体验kettle快捷调度方式

    https://my.oschina.net/u/944575/blog/1557410 kettle调度监控最佳实践 https://my.oschina.net/u/1026947/blog/15 ...

  3. VC++函数只被调用一次

    如何保证某个函数只被调用一次   一个函数caller会在其内部调用另外一个函数callee,现在的情况是,caller可能会在多个地方被多次调用,而你希望callee只在第一次被调用时被调用一次.一 ...

  4. Codeforces_765_D. Artsem and Saunders_(数学)

    D. Artsem and Saunders time limit per test 2 seconds memory limit per test 512 megabytes input stand ...

  5. 并发编程学习笔记(3)----synchronized关键字以及单例模式与线程安全问题

    再说synchronized关键字之前,我们首先先小小的了解一个概念-内置锁. 什么是内置锁? 在java中,每个java对象都可以用作synchronized关键字的锁,这些锁就被称为内置锁,每个对 ...

  6. java_IO_1

    public class DirStudy { public static void main(String[] args) { File file = new File("F:/Eclip ...

  7. spring aop 内部调用问题解决

    方法1: 基于 proxy 的 spring aop 带来的内部调用问题可以使用 AopContext.currentProxy() 强转为当前的再调用就可以解决了 例如: 错误用法:public A ...

  8. NOIP2000方格取数(洛谷,动态规划递推)

    先上题目: P1004 方格取数 下面上ac代码: ///如果先走第一个再走第二个不可控因素太多 #include<bits/stdc++.h> #define ll long long ...

  9. docker-compose 报错记录

    1.如往常一样对docker-compose.yml配置修改后,docker-compose up -d 后台启动,启动后报错,由原来的done变成了error. 第一反应就是down掉这些容器: d ...

  10. PAT 1129 Recommendation System

    Recommendation system predicts the preference that a user would give to an item. Now you are asked t ...