23种设计模式(18)java备忘录模式

 更新时间:2018年01月27日 09:58:28   作者:Java知音  
这篇文章主要为大家详细介绍了23种设计模式之java备忘录模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

23种设计模式第十八篇:java备忘录模式

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

类型:行为类

类图:

我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态。比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回。这时我们便可以使用备忘录模式来实现。

备忘录模式的结构

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

通用代码实现

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()); 
    } 
  } 
   
  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; 
    } 
  } 
  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(); 
      originator.setState("状态1"); 
      System.out.println("初始状态:"+originator.getState()); 
      Caretaker caretaker = new Caretaker(); 
      caretaker.setMemento(originator.createMemento()); 
      originator.setState("状态2"); 
      System.out.println("改变后状态:"+originator.getState()); 
      originator.restoreMemento(caretaker.getMemento()); 
      System.out.println("恢复后状态:"+originator.getState()); 
    } 
  }

        代码演示了一个单状态单备份的例子,逻辑非常简单:Originator类中的state变量需要备份,以便在需要的时候恢复;Memento类中,也有一个state变量,用来存储Originator类中state变量的临时状态;而Caretaker类就是用来管理备忘录类的,用来向备忘录对象中写入状态或者取回状态。

多状态多备份备忘录

       通用代码演示的例子中,Originator类只有一个state变量需要备份,而通常情况下,发起人角色通常是一个javaBean,对象中需要备份的变量不止一个,需要备份的状态也不止一个,这就是多状态多备份备忘录。
        实现备忘录的方法很多,备忘录模式有很多变形和处理方式,像通用代码那样的方式一般不会用到,多数情况下的备忘录模式,是多状态多备份的。其实实现多状态多备份也很简单,最常用的方法是,我们在Memento中增加一个Map容器来存储所有的状态,在Caretaker类中同样使用一个Map容器才存储所有的备份。下面我们给出一个多状态多备份的例子:

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()); 
    } 
    public String toString(){ 
      return "state1="+state1+"state2="+state2+"state3="+state3; 
    } 
  } 
  class Memento { 
    private Map<String, Object> stateMap; 
     
    public Memento(Map<String, Object> map){ 
      this.stateMap = map; 
    } 
   
    public Map<String, Object> getStateMap() { 
      return stateMap; 
    } 
   
    public void setStateMap(Map<String, Object> stateMap) { 
      this.stateMap = stateMap; 
    } 
  } 
  class BeanUtils { 
    public static Map<String, Object> backupProp(Object bean){ 
      Map<String, Object> result = new HashMap<String, Object>(); 
      try{ 
        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){ 
        e.printStackTrace(); 
      } 
      return result; 
    } 
     
    public static void restoreProp(Object bean, Map<String, Object> propMap){ 
      try { 
        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) { 
        e.printStackTrace(); 
      } 
    } 
  } 
  class Caretaker { 
    private Map<String, Memento> memMap = new HashMap<String, Memento>(); 
    public Memento getMemento(String index){ 
      return memMap.get(index); 
    } 
     
    public void setMemento(String index, Memento memento){ 
      this.memMap.put(index, memento); 
    } 
  } 
  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("001",ori.createMemento()); 
      ori.setState1("软件"); 
      ori.setState2("架构"); 
      ori.setState3("优秀"); 
      System.out.println("===修改后状态===\n"+ori); 
       
      ori.restoreMemento(caretaker.getMemento("001")); 
      System.out.println("===恢复后状态===\n"+ori); 
    } 
  }

备忘录模式的优缺点和适用场景

备忘录模式的优点有:

        当发起人角色中的状态改变时,有可能这是个错误的改变,我们使用备忘录模式就可以把这个错误的改变还原。
        备份的状态是保存在发起人角色之外的,这样,发起人角色就不需要对各个备份的状态进行管理。

备忘录模式的缺点有:

        在实际应用中,备忘录模式都是多状态和多备份的,发起人角色的状态需要存储到备忘录对象中,对资源的消耗是比较严重的。
        如果有需要提供回滚操作的需求,使用备忘录模式非常适合,比如jdbc的事务操作,文本编辑器的Ctrl+Z恢复等。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java中instanceof关键字实例讲解

    Java中instanceof关键字实例讲解

    大家好,本篇文章主要讲的是Java中instanceof关键字实例讲解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • Java查询Elasticsearch数据根据指定id检索(in查询)、sql权限过滤、多字段匹配检索及数据排序

    Java查询Elasticsearch数据根据指定id检索(in查询)、sql权限过滤、多字段匹配检索及数据排序

    在Java开发中Elasticsearch(简称ES)是一个非常流行的搜索引擎,它提供了强大的全文搜索和分析功能,这篇文章主要给大家介绍了关于Java查询Elasticsearch数据根据指定id检索(in查询)、sql权限过滤、多字段匹配检索及数据排序的相关资料,需要的朋友可以参考下
    2024-05-05
  • Maven依赖管理的用法介绍

    Maven依赖管理的用法介绍

    依赖管理是项目管理中非常重要的一环。几乎任何项目开发的时候需要都需要使用到库。而这些库很可能又依赖别的库,这样整个项目的依赖形成了一个树状结构,而随着这个依赖的树的延伸和扩大,一系列问题就会随之产生
    2022-08-08
  • Java 面向对象的特征解析与应用

    Java 面向对象的特征解析与应用

    Java 是面向对象的编程语言,对象就是面向对象程序设计的核心。所谓对象就是真实世界中的实体,对象与实体是一一对应的,也就是说现实世界中每一个实体都是一个对象,它是一种具体的概念
    2021-11-11
  • 举例讲解Java中final关键字的用法

    举例讲解Java中final关键字的用法

    Java中的final关键字可以被用来修饰变量、方法和类等,意味着终结、不可改变,下面我们就来举例讲解Java中final关键字的用法:
    2016-06-06
  • java的主要特性学习总结

    java的主要特性学习总结

    在本篇文章里小编给大家分享了一篇关于java的主要特性学习总结内容,有兴趣的朋友们可以参考下。
    2020-05-05
  • 带你盘点Java的五种运算符

    带你盘点Java的五种运算符

    这篇文章主要介绍了Java基本数据类型和运算符,结合实例形式详细分析了java基本数据类型、数据类型转换、算术运算符、逻辑运算符等相关原理与操作技巧,需要的朋友可以参考下
    2021-07-07
  • Springboot 整合 RocketMQ 收发消息的配置过程

    Springboot 整合 RocketMQ 收发消息的配置过程

    这篇文章主要介绍了Springboot 整合 RocketMQ 收发消息,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • java中Class.forName的作用浅谈

    java中Class.forName的作用浅谈

    这篇文章介绍了java中Class.forName的作用,有需要的朋友可以参考一下
    2013-11-11
  • springboot 实现Http接口加签、验签操作方法

    springboot 实现Http接口加签、验签操作方法

    这篇文章主要介绍了springboot 实现Http接口加签、验签操作,服务之间接口调用,通过签名作为安全认证来保证API的安全性,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-09-09

最新评论