摘要:本文深入浅出的讲述了设计模式中的 备忘录 模式 , 并给出了简单的示例 , 例子浅显易懂 , 并附带源代码。 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

       备忘录模式属于行为型模式,其意图是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将对象恢复到原先保存的状态。有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作,或从错误中恢复过来,需要实现检查点和取消机制,而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到他们先前的状态。但是对象通常封装了其部分或所有的状态信息,使得其状态不能被其他的对象访问。也就不可能在该对象之外保存其状态。而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。

      

适用性:

l         必须保存一个对象在某一个时刻的状态,这样以后需要时它才能恢复到先前的状态。

l         如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性
1Memento 的类图

协作关系是:客户端每操作一步 Employee (原发器)的信息,便产生一个 Memento 对象,并把 Memento 对象发送给 CareTaker 保存,当需要恢复的时候便从 CareTaker 对象中取出 Memento 对象,进行状态的恢复。

参与者:

       Memento (备忘录 Memento ):

备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。

       防止原发器之外的其他对象访问备忘录,备忘录实际上有两个接口,管理者 CareTaker 只能看到备忘录的窄接口 -- 它只能将备忘录传递给其他对象。相反,原生器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只能允许生成备忘录的那个原发器访问本备忘录的内部状态。

 

Originator( 原发器,如 Employee)

       原发器创建一个备忘录,用以记录当前时刻它的内部状态。

       使用备忘录恢复内部的状态。

CareTaker (负责人 ):

       负责保存好备忘录。

       不能对备忘录的内容进行操作或检查。

 

效果:

       备忘录模式有以下的一些效果:

1)  保持封装的边界: 使用备忘录可以避免暴露一些只应有原发器管理却又必须存储在原发器之外的信息。该模式把可能很复杂的 Originator 内部信息对其他对象屏蔽起来,从而保持了封装的边界。

2)  它简化了原发器 在其他的保持封装性的设计中, originator 负责保持客户请求过的内部状态版本。这就把所有存储管理的重任务交给了 Originator 。让客户管理他们请求的状态将会简化 Originator, 并且使得客户工作结束时无需通知原发器。

3)  使用备忘录可能代价很高 如果原发器在生成备忘录时必须拷贝并存储大量的信息,或者客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销。除非封装和恢复 Originator 状态的开销不大,否则该模式可能并不适合。

4)  定义窄接口和宽接口 在一些语言中可能难以保证只有原发器可访问备忘录的状态。

5)  维护备忘录的潜在代价 管理器负责删除它所维护的备忘录。然而 ,管理器不知道备忘录中有多少个状态,因此当存储备忘录时,一个本来很小的管理器,可能会产生大量的存储开销。

相关的代码:

Memento 代码:

       package memento;

public class Memento{

    String name ;

    int age ;

    public Memento(String name, int age){

       this . name = name;

       this . age = age;

    }

}

Employee 模式:

package memento;

public class Employee{

    private String name ;

    private int age ;

    public Employee(String aName, int aAge){

       name = aName;

       age = aAge;

    }

    public void setName(String aName){

       name = aName;

    }

    public void setAge( int aAge){

       age = aAge;

    }

    public Memento  saveMemento(){

       return new Memento( name , age );

    }

    public void restoreMemento(Memento memento){

       age = memento. age ;

       name = memento. name ;

    }

    public int getAge(){

       return age ;

    }

    public String getName(){

       return name ;

    }

}

CareTaker 代码:

package memento;

import java.util.Vector;

public class CareTaker{

    private Vector v ;

    private int   current ;

    public CareTaker(){

       current = -1;

       v = new Vector();

    }

    public void setMemento(Memento mem){

       for ( int i = current +1;i< v .size();i++)

           v .remove(i);

       current ++;

       v .add(mem);

    }

    public Memento getMemento(){

       if ( current >0){

           current --;

           return (Memento) v .get( current );

       }

       return null ;

    }

}

Client 代码:

package memento;

public class Client{

    public static void show(Employee e){

       System. out .println( "-----------------------------------" );

       System. out .println( "Name:" +e.getName());

       System. out .println( "Age:" + e.getAge());

       System. out .println( "-----------------------------------" );

    }

    public static void main(String[] args){

       Employee e = new Employee( "lili" ,25);

       CareTaker ct = new CareTaker();

       show(e);

       ct.setMemento(e.saveMemento());

       e.setName( "litianli" );

       show(e);

       ct.setMemento(e.saveMemento());

       e.setAge(45);

       show(e);

       ct.setMemento(e.saveMemento());

       //restore

       e.restoreMemento(ct.getMemento());

       show(e);

       e.restoreMemento(ct.getMemento());

       show(e);

    }

}

       

总结:备忘录模式保存了对象的内部状态改变信息,提供了撤销和重做动作所需要的所有数据,与 Command 模式比较类似。