备忘录模式 - Memento Pattern,一种弥补真实世界缺陷的方法,一个对象的备份模式,提供一种程序数据的备份方法

WHAT

定义

Without violating encapsulation, capture and externalize an object's internal state so that object can be restored to this state later.

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

类图

Originator 发起人角色

记录当前时刻的内部状态

负责定义哪些属于备份范围的状态

负责创建和恢复备忘录数据

public class Originator {
  // 内部状态
  private String state = "";
  
  public String getState(){
    return state;
  }
  public void setState(String state){
    this.state = state;
  }
  // 创建一个备忘录
  public Memento createMemento(){
    return new Memento(this.state);
  }
  // 恢复一个备忘录
  public void restoreMemento(Memento _memento){
    this.setState(_memento.getState());
  }
}

Memento备忘录角色

负责存储Originator发起人对象的内部状态

在需要的时候提供发起人需要的内部状态

public class Memento{
  // 发起人的内部状态
  private String state = "";
  //构造函数传递参数
  public Memento(String _state){
    this.state = _state;
  }
  public String getState(){
    return state;
  }
  public void setState(String state){
    this.state = state;
  }
}

Caretaker备忘录管理员角色

对备忘录进行管理、保存和提供备忘录

public class Caretaker {
  // 备忘录对象
  private Memento memento;
  
  public Memento getMemento(){
    return memento;
  }
  
  public void setMemento(Memento memento){
    this.memento = memento;
  }
}

场景类

public class Client {
  public static void main(String[] args){
    // 定义发起人
    Originator originator = new Originator();
    // 定义备忘录管理员
    Caretaker caretaker = new Caretaker();
    //创建一个备忘录
    caretaker.setMemento(originator.createMemento());
    //恢复一个备忘录
    originator.restoreMemento(caretaker.getMemento());
  }
}

WHY

HOW

使用场景

  • 需要保存和恢复数据的相关状态场景
  • 提供一个可回滚的操作
  • 需要监控的副本场景中
  • 数据库连接的事务管理

注意事项

备忘录的生命期

备忘录创建出来就要在“最近”的代码中使用,要主动管理它的生命周期,建立就要使用,不用就立即删除其引用,等待垃圾回收器对它的回收处理

备忘录的性能

不要在频繁建立对象的场景中是使用备忘录模式 —— 比如for循环中

  • 控制不了备忘录建立的对象数量
  • 大对象的建立是要消耗资源的

扩展

clone方式的备忘录

类图

备忘录和发起人角色融合
public class Originator implements Coneable {
  private Originator backup;
  // 内部状态
  private String state = "";
  
  public String getState() {
    return state;
  }
  
  public void setState(String state){
    this.state = state;
  }
  
  // 创建一个备忘录
  public void createMemeto(){
    this.backup = this.clone();
  }
  //恢复一个备忘录
  public void restoreMemento(){
    this.setState(this.backup.getState());
  }
  // 克隆当前对象
  @Override
  protected Originator clone(){
    try{
      return (Originator)super.clone();
    }catch(CloneNotSupportedException e){
      e.printStackTrace();
    }
    return null;
  }
  
}
备忘录管理员
public class Caretaker {
  // 发起人对象
  private Originator originator;
  public Originator getOriginator(){
    return originator;
  }
  public void setOriginator(Originator originator){
    this.originator = originator;
  }
}
场景类
public class Client{
  public static void main(String[] args){
    // 定义发起人
    Originator originator = new Originator();
    //建立初始状态
    originator.setState("初始状态...");
    System.out.println("初始化状态是:" + originator.getState());
    // 建立备份
    originator.createMemento();
    //修改状态
    originator.setState("修改后的状态...");
    System.out.println("修改后状态是:" + originator.getState());
    //回复原有状态
    originator.restoreMemento();
    System.out.println("恢复后状态是:" + originator.getState());
  }
}

考虑到深拷贝和浅拷贝的问题,建议Clone方式的备忘录模式适用于较简单的场景。尽量不要与其他对象产生严重的耦合关系。


《设计模式之禅》 第24章备忘录模式