七、备忘录模式Memento(行为型模式)

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

在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、客户端为发起人角色创建一个备忘录对象。

2、调用发起人对象的某个操作,这个操作是可以撤销的。

3、检查发起人对象所出状态的有效性。检查的方式可以是发起人对象的内部自查,也可以由某个外部对象进行检查。

4、如果需要的话,将发起人的操作撤销,也就是说根据备忘录对象的记录,将发起人对象的状态恢复过来。

“假如”协议模式的操作过程:

1、将发起人对象做一个拷贝。

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

3、检查这个拷贝的状态是否有效和自恰。

4、如果检查结果是无效或者不自恰的,那么扔掉这个拷贝,并触发异常处理程序;相反,如果检查是有效和自恰的,那么在原对象上执行这个操作

显然这一做法对于撤销一个操作并恢复操作前状态较为复杂和困难的发起人对象来说是一个较为谨慎和有效的做法。

“假如”协议模式的优点和缺点

具体来说,这个做法的长处是可以保证发起人对象永远不会处于无效或不自恰的状态上,这样作的短处是成功的操作必须执行两次。

如果操作的成功率较低的话,这样做就比较划算,反之就不太划算。

使用备忘录模式的优点和缺点

一、备忘录模式的优点

1、有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,

使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。

2、本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需

要的这些状态的版本。

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)窄接口或者黑箱实现:

//客户端

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;">		     //将会造成客户端和备忘录对象持有对同一个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);
			}
		}
		
//客户端
		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)自述历史模式(备忘录模式的一个变种)

由于“自述历史”作为一个备忘录模式的特殊实现形式非常简单易懂,它可能是备忘录模式最为流行的实现形式。

//窄接口
		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;
				}
			}
		}
//客户端
		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);
			}
		}

时间: 2024-10-16 04:31:41

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

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

Memento 备忘录模式(行为型模式) 对象状态的回溯 对象状态的变化无端,如何回溯.恢复对象在某个点的状态? 动机(Motivation) 在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态.如果使用一些共有接口来让其他对象得到对象的状态,便会暴露对象的细节实现. 如何实现对象状态良好保存与恢复?同时又不会因而破坏对象本身的封装性. 意图(Intent) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样

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

Interpreter 解释器模式(行为型模式) 动机(Motivation) 在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化. 在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的. 意图(Intent) 给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器用来解释语言中的句子.——<设计模式>GoF 中文数字转换为阿拉伯数字 public

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

Command 命令模式(行为型模式) 耦合与变化 耦合是软件不能抵御变化的根本性原因.不仅实体对象与实体对象之间存在耦合关系,实体对象与行为操作之间也存在耦合关系. 动机(Motivation) 在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”.但在某些场合——比如对行为进行“记录.撤销/重做(undo/redo).事务”等处理,这种无法抵御变化的紧耦合是不合适的. 在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的解耦. 意

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

Chain Of Responsibility 职责链模式(行为型模式) 请求的发送者与接受者 某些对象请求的接受者可能有多种多样,变化无常…… 动机(Motivation) 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合. 如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦. 意图(Intent) 使多个对象都有机会处理请求,从而避免请求的发送者和接受者

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

Strategy 策略模式(行为型模式) 动机(Motivation) 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂:而且有时候支持不使用的算法也是一个性能负担. 如何在运行时根据需要透明地更改算法?将算法与对象本身解耦,从而避免上述问题? 意图(Intent) 定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换.该模式使得算法可以独立于使用它的客户而变化.——<设计模式>GoF 示例代码 enum CartType

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

Visitor 访问者模式(行为型模式) 动机(Motivation)在软件构造过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的修改,将会给子类带来繁重的变更负担,甚至破坏原有设计. 如果在不变更类层次结构的前提下,在运行时更加需要透明地为类层次结构上的各个类活动添加新的操作,从而避免上述问题? 意图(Intent) 表示一个作用于某种对象结构中各元素的操作.它可以在不改变各元素的类的前提下定义作用于这些元素的新操作.——<设计模式>GoF 示例代

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

State 状态模式(行为型模式) 动机(Motivation) 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态的行为就可能完全不同. 如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转换之间引入紧耦合? 意图(Intent) 允许一个对象在其内部状态改变时改变它的行为.从而使对象看起来似乎修改了其行为.——<设计模式>GoF 结构(Structure) 示例代码 public enum Document

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

Iterator 迭代器模式(行为型模式) 动机(Motivation) 在软件构建过程中,集合对象内部结构常常变化各异.但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码可以透明地访问其包含的元素:同时这种“透明变量”也为“同一种算法在多种集合对象上进行操作”提供了可能. 使用面向对象技术使这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式. 意图(Intent)提供一种方法顺序访问一个聚合对象中各个元素 , 而又不需暴露该对象的内部表示.——

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

Mediator 中介者模式(行为型模式) 依赖关系的转化 动机(Motivation) 在软件构建过程中,经常出现多个对象互相关联交互的情况,对象之间经常会维持一种复杂的应用关系,如果遇到一些需求的更改,这种直接的引用将面临不断的变化. 在这种情况下,我们可以使用一个“中介对象”来管理对象间的关联关系,避免相互的对象之间的紧耦合引用关系,从而更好地抵御变化. 意图(Intent) 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显示的相互引用,从而使其耦合松散,而且可以独立地改变它们

设计模式-04 建造者模式(创建型模式)

一 建造者模式 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 主要解决:在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定. 关键代码 : 建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系. 使用场景: 汽车有很多部件,车轮