zoukankan      html  css  js  c++  java
  • 备忘录模式


    备忘录模式

    • 备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态(其实不一定是在对象之外,可以是类自主备份和恢复),这样以后就可以将该对象恢复到原先保存的状态。
    • 通俗的说备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法,其通用类图如下:

      •  Originator发起人角色:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。
      • Memento备忘录角色:负责存储Originator发起人的内部状态,在需要时提供发起人需要的内部状态。
      • Caretaker备忘录管理员角色:对备忘录进行管理,保存和提供备忘录。
      • 其通用类图的源码如下:
    • public class Originator {
          private String state = "very goood";
          public void setState(String newState){
              this.state = newState;
          }
          public String getState(){
              return this.state;
          }
          public Memento createMemento(){
              return new Memento(this.state);
          }
          public void restoreState(Memento _memento){
              this.setState(_memento.getState());
          }
      }
      
      public class Memento {
          private String state;
          public Memento(String state){
              this.state = state;
          }
          public String getState(){
              return this.state;
          }
      }
      
      public class Caretaker {
          private Memento _memento = null;
          public void setMemento(Memento memento){
              this._memento = memento;
          }
          public Memento getMemento(){
              return this._memento;
          }
      }
      
      public class Client {
      
          /**
           * @param args
           */
          public static void main(String[] args) {
              // TODO Auto-generated method stub
              Originator originator = new Originator();
              Caretaker _caretaker = new Caretaker();
              _caretaker.setMemento(originator.createMemento());
              originator.setState("very bad");
              System.out.println(originator.getState());
              originator.restoreState(_caretaker.getMemento());
              System.out.println(originator.getState());
          }
      }
      View Code
    • 由于备忘录模式有很多变形和处理,每种方式都有自身的优点和缺点,标准模式很难在项目中遇到,基本上都是一些变换处理。备忘录模式主要适用于:1、需要保存和恢复数据的场景;2、提供一个可回滚的操作,如win常见的Ctrl+Z,浏览器中的后退按钮,文本管理器上的backspace键等;3、需要监控副本的场景。例如监控一个对象的属性,但是监控又不应该作为系统的主要业务来调用,即使出现监控不准、错误报警也影响不大,因此一般的做法是备份一个主线程中的对象,然后由分析程序分析;4、数据库连接的事务管理就是用的备忘录模式。
    备忘录模式的扩展
    • clone方式的备忘录模式

    在原型模式中,我们通过clone的方式产生一个对象的内部状态,这也是很好的一个备份方式,发起人角色只要实现Cloneable就成,其通用类图如下:

    public class Originator implements Cloneable{
        private String state = "very good";
        public void setState(String newState){
            this.state = newState;
        }
        public String getState(){
            return this.state;
        }
        public Originator createMemento(){
            return this.clone();
        }
        public void restoreState(Originator originator){
            this.setState(originator.getState());
        }
        @Override
        protected Originator clone(){
            try {
                return (Originator) super.clone();
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    }
    
    public class Caretaker {
        private Originator originator = null;
        public void setOriginator(Originator originator){
            this.originator = originator;
        }
        public Originator getOriginator(){
            return this.originator;
        }
    }
    
    public class Client {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Originator _originator = new Originator();
            Caretaker caretaker = new Caretaker();
            caretaker.setOriginator(_originator.createMemento());
            _originator.setState("very bad");
            System.out.println(_originator.getState());
            _originator.restoreState(caretaker.getOriginator());
            System.out.println(_originator.getState());;
        }
    }
    View Code

    当然了发起人还可以自主备份和恢复,具体代码如下:

    public class Originator3 implements Cloneable{
        private Originator3 backup = null;
        private String state = "very bad";
        public void setState(String newState){
            this.state = newState;
        }
        public String getState(){
            return this.state;
        }
        public void createMemento(){
            this.backup = this.clone();
        }
        public void restoreState(){
            this.setState(this.backup.getState());
        }
        protected Originator3 clone(){
            try {
                return (Originator3) super.clone();
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    }
    View Code
    • 多状态的备忘录模式

    如上我们讲解的都是单状态的情况,而在实际的开发中一个对象很可能有很多状态,一个JavaBean有多个属性是很常见的。因此我们讲解一个对象全状态备份方案,他有多种处理方式,比如使用clone的方式就可以解决,使用数据技术也可以解决(DTO回写到临时表中)等,如下方法是实现一个JavaBean对象的所有状态的备份和还原,类图如下所示:

    public class Originator4 {
        private String state1 = null;
        private String state2 = null;
        private String state3 = null;
        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 Memento4 createMemento(){
            return new Memento4(BeanUtils.backup(this));
        }
        public void restoreMemento(Memento4 _memento){
            BeanUtils.restoreMap(this, _memento.getStateMap());
        }
    }
    
    public class BeanUtils {
        public static HashMap<String,Object> backup(Object bean){
            HashMap<String,Object> map = new HashMap<String,Object>();
            try {
                BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
                PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
                for(PropertyDescriptor des : descriptors){
                    //读取属性的名称
                    String fileName = des.getName();
                    //读取属性的方法
                    Method getter = des.getReadMethod();
                    Object fieldValue = getter.invoke(bean, new Object[]{});
                    if(!fileName.equalsIgnoreCase("class"))
                        map.put(fileName, fieldValue);
                }
            } catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return map;
        }
        public static void restoreMap(Object bean, HashMap<String,Object> map){
            try {
                BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
                //获取属性描述
                PropertyDescriptor[] descriptor = beanInfo.getPropertyDescriptors();
                for(PropertyDescriptor des : descriptor){
                    //属性名称
                    String fileName = des.getName();
                    if(map.containsKey(fileName)){
                        Method setter = des.getWriteMethod();
                        setter.invoke(bean, new Object[]{map.get(fileName)});
                    }
                }
            } catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    public class Memento4 {
        private HashMap<String,Object> stateMap;
        public Memento4(HashMap<String,Object> map){
            this.stateMap = map;
        }
        public HashMap<String,Object> getStateMap(){
            return this.stateMap;
        }
    }
    
    public class Caretaker4 {
        private Memento4 _memento = null;
        public void setMemento(Memento4 memento){
            this._memento = memento;
        }
        public Memento4 getMemento(){
            return this._memento;
        }
    }
    
    public class Client {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Originator4 originator = new Originator4();
            Caretaker4 caretaker = new Caretaker4();
            caretaker.setMemento(originator.createMemento());
            originator.setState1("haha");
            originator.setState2("heihei");
            originator.setState3("hehe");
            originator.restoreMemento(caretaker.getMemento());
        }
    }
    View Code
    •  多备份的备忘录

    如上的解决方法中还不能做到将备份的上一个状态还原,因为如上的每个对象只有个备份,那么我们把对象的状态还原到某个点怎么办呢?这就需要对每一个对象进行多备份。首先我们介绍一个名词,检查点(Check Point),也就是备份的时候的戳记,系统级的备份一般是时间戳,如下在设计的时候检查点是一个唯一的标识字符串。只需要对多状态备忘录模式中的Caretaker中的代码做如下修改就可以,修改后的代码如下:

    public class Caretaker4 {
        private HashMap<String,Memento4> _mementoMap = new HashMap<String,Memento4>();
        public void setMemento(String id,Memento4 memento){
            this._mementoMap.put(id, memento);
        }
        public Memento4 getMemento(String id){
            return this._mementoMap.get(id);
        }
    }
    
    public class Client {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Originator4 originator = new Originator4();
            Caretaker4 caretaker = new Caretaker4();
            caretaker.setMemento("001",originator.createMemento());
            originator.setState1("haha");
            originator.setState2("heihei");
            originator.setState3("hehe");
            caretaker.setMemento("002", originator.createMemento());
            originator.restoreMemento(caretaker.getMemento("001"));
        }
    }
    View Code
    • 设计具有更好的封装性

  • 相关阅读:
    结构体
    指针
    数组
    银行取款机系统
    函数
    基础
    IOS系统的安装和Vi的操作模式以及简单的指令
    1203.4——循环语句 之 for
    1203.3——循环语句 之 while
    1203.2——条件语句 之 switch语句
  • 原文地址:https://www.cnblogs.com/zhanglei93/p/6095712.html
Copyright © 2011-2022 走看看