备忘录模式

备忘录模式

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

1. UML类图

2. 定义

通俗地说,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法

  • Originator发起人角色:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和备份备忘录数据
  • Memento备忘录角色:负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的状态
  • Caretaker备忘录管理员角色:对备忘录进行管理、保存和提供备忘录

3. 通用代码

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

//备忘录角色
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;
  }
}

//备忘录管理员角色
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.getMementor());
  }
}

4. 应用

4.1 使用场景

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

4.2 注意事项

  • 备忘录的生命期:备忘录创建出来就要在“最近”的代码中使用,要主动管理它的声明周期
  • 备忘录的性能:不要再频繁建立备份的场景中使用备忘录模式,原有有
    • 控制不了备忘录建立的对象数量
    • 大对象的建立是要消耗资源的,系统的性能需要考虑

5. 扩展

5.1 clone方式的备忘录

精简了程序,高层模块的依赖也少了,可用于比较简单的场景或者比较单一的场景中,尽量不要与其他的对象产生耦合关系

//发起人自主备份和恢复
public class Originator implements Cloneable{  
  private Originator backup;  
  //内部状态  
  private String state = "";  
  public String getState() {  
     return state;  
  }  
  public void setState(String state) {  
    this.state = state;  
  }  
  //创建一个备忘录  
  public void createMemento(){  
    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 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());  
    }
}

5.2 多状态的备忘录模式

如果要设计一个在运行期决定备份状态的框架,则建议采用AOP框架来实现,避免采用动态代理无谓地增加程序逻辑复杂性

//发起者
public class Originator {  
  //内部状态  
  private String state1 = "";  
  private String state2 = "";  
  private String state3 = "";  
  public String getState1() {  
    return state1;  
  }  
  public void setState1(String state1) {  
      this.state1 = state1;  
  }  
  public String getState2() {  
     return state2;  
  }  
  public void setState2(String state2) {  
      this.state2 = state2;  
  }  
  public String getState3() {  
      return state3;  
  }  
  public void setState3(String state3) {  
      this.state3 = state3;  
  }  
  //创建一个备忘录  
  public Memento createMemento(){  
     return new Memento(BeanUtils.backupProp(this));  
  }  
  //恢复一个备忘录  
  public void restoreMemento(Memento _memento){  
    BeanUtils.restoreProp(this, _memento.getStateMap());  
  }  
  //增加一个toString方法  
  @Override  
  public String toString(){  
    return "state1=" +state1+"\nstat2="+state2+"\nstate3="+state3;
  }
}  

//BeanUtils工具类
public class BeanUtils {  
  //把bean的所有属性及数值放入到Hashmap中  
  public static HashMap backupProp(Object bean){  
    HashMap result = new HashMap();  
    try {  
        //获得Bean描述  
        BeanInfo beanInfo=Introspector.getBeanInfo(bean.getClass());  
        //获得属性描述  
        PropertyDescriptor[] descriptors=beanInfo.getPropertyDescriptors();  
        //遍历所有属性  
        for(PropertyDescriptor des:descriptors){  
            //属性名称  
            String fieldName = des.getName();  
            //读取属性的方法  
            Method getter = des.getReadMethod();  
            //读取属性值  
            Object fieldValue=getter.invoke(bean,new Object[]{});  
            if(!fieldName.equalsIgnoreCase("class")){  
              result.put(fieldName, fieldValue);  
            }  
        }  
    } catch (Exception e) {  
    //异常处理  
    }  
    return result;  
  }  
  //把HashMap的值返回到bean中  
  public static void restoreProp(Object bean,HashMap propMap){  
      try {  
        //获得Bean描述  
        BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());  
        //获得属性描述  
        PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();  
        //遍历所有属性  
        for(PropertyDescriptor des:descriptors){  
          //属性名称  
          String fieldName = des.getName();  
          //如果有这个属性  
          if(propMap.containsKey(fieldName)){  
            //写属性的方法  
            Method setter = des.getWriteMethod();  
            setter.invoke(bean, new Object[]{propMap.get(fieldName)});  
          }  
        }  
      } catch (Exception e) {  
          //异常处理  
          System.out.println("shit");  
          e.printStackTrace();  
      }  
  }  
}

//备忘录角色
public class Memento {  
    //接受HashMap作为状态  
    private HashMap stateMap;  
    //接受一个对象,建立一个备份  
    public Memento(HashMap map){  
        this.stateMap = map;  
    }  
    public HashMap getStateMap() {  
        return stateMap;  
    }  
    public void setStateMap(HashMap stateMap) {  
        this.stateMap = stateMap;  
    }  
}

//场景类
public class Client {  
    public static void main(String[] args) {  
        //定义出发起人  
        Originator ori = new Originator();  
        //定义出备忘录管理员  
        Caretaker caretaker = new Caretaker();  
        //初始化  
        ori.setState1("中国");  
        ori.setState2("强盛");  
        ori.setState3("繁荣");  
        System.out.println("===初始化状态===\n"+ori);  
        //创建一个备忘录  
        caretaker.setMemento(ori.createMemento());  
        //修改状态值  
        ori.setState1("软件");  
        ori.setState2("架构");  
        ori.setState3("优秀");  
        System.out.println("\n===修改后状态===\n"+ori);  
        //恢复一个备忘录  
        ori.restoreMemento(caretaker.getMemento());  
        System.out.println("\n===恢复后状态===\n"+ori);  
    }  
}

5.3 多备份的备忘录

检查点(Check Point),也就是你在备份的时候做的戳记,系统级的备份一般是时间戳, 我们只要把通用代码中的Caretaker管理员稍做修改就可以了

可能出现内存溢出问题,该备份一旦产生就装入内存,没有任何销毁的意向,非常危险。所以建议限制Map的上限

//备忘录管理员
public class Caretaker {  
    //容纳备忘录的容器  
    private HashMap memMap = new HashMap();  
    public Memento getMemento(String idx) {  
         return memMap.get(idx);  
    }  
    public void setMemento(String idx,Memento memento) {  
        this.memMap.put(idx, memento);  
    }  
}

//场景类
public class Client {  
    public static void main(String[] args) {  
        //定义出发起人  
        Originator originator = new Originator();  
        //定义出备忘录管理员  
        Caretaker caretaker = new Caretaker();  
        //创建两个备忘录  
        caretaker.setMemento("001",originator.createMemento());  
        caretaker.setMemento("002",originator.createMemento());  
        //恢复一个指定标记的备忘录  
        originator.restoreMemento(caretaker.getMemento("001"));  
    }  
}

5.4 封装得更好一点

一个备份的数据是完全、绝对不能修改的,它保证数据的洁净,避免数据污染而使备份失去意义备份是不能被篡改的,也就是说需要缩小备份出的备忘录的阅读权限,保证只能是发起人可读就成

这里通过内置了Memento来实现,设置成private禁止他人访问,产生关联关系则通过空接口来处理。它具有公共的访问权限

Originator {  
    //内部状态  
    private String state = "";  
    public String getState() {  
        return state;  
    }  
    public void setState(String state) {  
        this.state = state;  
    }  
    //创建一个备忘录  
    public IMemento createMemento(){  
        return new Memento(this.state);  
    }  
    //恢复一个备忘录  
    public void restoreMemento(IMemento _memento){  
        this.setState(((Memento)_memento).getState());  
    }  
    //内置类  
    private class Memento implements IMemento{  
        //发起人的内部状态  
        private String state = "";  
        //构造函数传递参数  
        private Memento(String _state){  
            this.state = _state;  
        }  
        private String getState() {  
            return state;  
        }  
        private void setState(String state) {  
            this.state = state;  
        }  
    }  
}

//备忘录的空接口
public interface IMemento {  
}

//备忘录管理者
public class Caretaker {  
    //备忘录对象  
    private IMemento memento;  
    public IMemento getMemento() {  
        return memento;  
    }  
    public void setMemento(IMemento memento) {  
        this.memento = memento;  
    }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值