Momemto Pattern 备忘录模式

主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作。 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

Momento Pattern的角色

  1. 备忘录(Memento)角色:备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口,“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。
  2. 备忘发起(Originator)角色:“备忘发起角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。
    • 创建一个含有当前的内部状态的备忘录对象。
    • 使用备忘录对象存储其内部状态。
  3. 备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。
    • 负责保存备忘录对象。
    • 不检查备忘录对象的内容。

Momento Pattern的实现流程

白箱模式

  • 备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。因此这个实现又叫做“白箱实现”。“白箱”实现将发起人角色的状态存储在一个大家都看得到的地方,因此是破坏封装性的。 白箱模式
    1. 备忘录
      public class Momemto {
        private int state;
        public Momemto(int state){
         this.state = state;
         System.out.println("Momento: Saved state - " + state);
        }
        public int getState() {
         return state;
        }
        public void setState(int state) {
         this.state = state;
        }
      }
      
  1. 备忘录的发起者
    public class Originator {
     private int state = 0;
     public Momemto createMomento(){
         return new Momemto(state);
     }
     public void restoreMomento(Momemto momemto){
         this.state = momemto.getState();
         System.out.println("Originator: Restored state - " + this.state + " from momemto.");
     }
     public int getState() {
         return state;
     }
     public void setState(int state) {
         this.state = state;
     }
     public static void main(String[] args) {
         Originator originator = new Originator();	//Momento的发起者,要存储他的对象
         Momemto momento = originator.createMomento();
         CareTaker careTaker = new CareTaker();	//备忘录的保存者,可以用一种数据结构存储备忘录。
         careTaker.setMomemto(momento);
         originator.setState(1);
         System.out.println("Current state: " + originator.getState());
         originator.restoreMomento(careTaker.getMomemto());	//回复备忘录的备份。
         System.out.println("Current state: " + originator.getState());
     }
    }
    Momento: Saved state - 0
    Current state: 1
    Originator: Restored state - 0 from momemto.
    Current state: 0
    
  2. Mememto 的保存者
    public class CareTaker {
     private Momemto momemto;
     public Momemto getMomemto() {
         return momemto;
     }
     public void setMomemto(Momemto momemto) {
         this.momemto = momemto;
     }
    }
    

黑箱模式

备忘录角色对发起人(Originator)角色对象提供一个宽接口,而为其他对象提供一个窄接口。这样的实现叫做“黑箱实现”。 在JAVA语言中,实现双重接口的办法就是将备忘录角色类设计成发起人角色类的内部成员类。

  1. 备忘录的发起者
    public class Originator {
     private int state = 0;
     public int getState() {
         return state;
     }
     public void setState(int state) {
         this.state = state;
     }
     public Momento createMomento(){
         return new Momento(this.state);
     }
     public void restoreMomento(IMomento momento){
         this.setState(((Momento)momento).getState());
     }
     private class Momento implements IMomento{	//备忘录作为发起者的私有内部类,在外界持有的是IMomento的接口,无法被强转成Momento类型,实现了外部不可见而内部可见。
         private int state;
         public int getState() {
             return state;
         }
         public void setState(int state) {
             this.state = state;
         }
         public Momento(int state){
             this.state = state;
             System.out.println("Momento: Saved state - " + state);
         }
     }
    }
    
  2. Momento的保存者
    public class CareTaker {
     private IMomento momento;	//持有的是接口而不是实现类,所以对于Momento内部不可见。
     public IMomento getMomento() {
         return momento;
     }
     public void setMomento(IMomento momento) {
         this.momento = momento;
     }
    }
    
  3. 测试类(该用例的测试类如果写在Originator内部,就可以访问内部类的对象,就实现不了黑盒)
    public class Test {
     public static void main(String[] args) {
         Originator originator = new Originator();
         CareTaker ct = new CareTaker();
         IMomento momento = ct.getMomento();	//此处momento无法被强转成Momento对象
         ct.setMomento(originator.createMomento());
         originator.setState(3);
         System.out.println("Current state: " + originator.getState());
         originator.restoreMomento(ct.getMomento());
         System.out.println("Current state: " + originator.getState());
     }
    }
    Momento: Saved state - 0
    Current state: 3
    Current state: 0
    

多重检查点

前面所给出的白箱和黑箱的示意性实现都是只存储一个状态的简单实现,也可以叫做只有一个检查点。常见的系统往往需要存储不止一个状态,而是需要存储多个状态,或者叫做有多个检查点。   备忘录模式可以将发起人对象的状态存储到备忘录对象里面,备忘录模式可以将发起人对象恢复到备忘录对象所存储的某一个检查点上。

“自述历史”模式

所谓“自述历史”模式(History-On-Self Pattern)实际上就是备忘录模式的一个变种。在备忘录模式中,发起人(Originator)角色、负责人(Caretaker)角色和备忘录 (Memento)角色都是独立的角色。虽然在实现上备忘录类可以成为发起人类的内部成员类,但是备忘录类仍然保持作为一个角色的独立意义。在“自述历 史”模式里面,发起人角色自己兼任负责人角色。

Reference

  1. 23种设计模式之—备忘录模式