Java设计模式之备忘录模式_动力节点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设计模式之备忘录模式_动力节点Java学院,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 详解Java设计模式之备忘录模式的使用

    定义与结构     备忘录(Memento)模式又称标记(Token)模式.GOF给备忘录模式的定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 在讲命令模式的时候,我们曾经提到利用中间的命令角色可以实现undo.redo的功能.从定义可以看出备忘录模式是专门来存放对象历史状态的,这对于很好的实现undo.redo功能有很大的帮助.所以在命令模式中undo.redo功能可以配合备忘录模式来实现. 其实单就实现保存一个对

  • JAVA设计模式之备忘录模式原理与用法详解

    本文实例讲述了JAVA设计模式之备忘录模式.分享给大家供大家参考,具体如下: 备忘录模式:又叫做快照模式,指在不破坏封装性的前提下,获取到一个对象的内部状态,并在对象之外记录或保存这个状态.在有需要的时候可将该对象恢复到原先保存的状态.我们相当于把对象原始状备份保留,所以叫备忘录模式. *模式 角色对象组成: 1.发起者对象:负责创建一个备忘录来记录当前对象的内部状态,并可使用备忘录恢复内部状态. 2.备忘录对象:负责存储发起者对象的内部状态,并防止其他对象访问备忘录. 3.管理者对象:负责备忘

  • Java设计模式之备忘录模式(Memento模式)介绍

    Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: 复制代码 代码如下: public class Originator { private int number; private File file = null; public Originator(){} // 创建一个Memento public Memento getMemento(){ return new Me

  • 详解备忘录模式及其在Java设计模式编程中的实现

    1. 定义 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 2. 使用的原因 想要恢复对象某时的原有状态. 3. 适用的情况举例 有很多备忘录模式的应用,只是我们已经见过,却没细想这是备忘录模式的使用罢了,略略举几例: eg1. 备忘录在jsp+javabean的使用: 在一系统中新增帐户时,在表单中需要填写用户名.密码.联系电话.地址等信息,如果有些字段没有填写或填写错误,当用户点击"提交"按钮时,需要在新增页面

  • Java设计模式之备忘录模式_动力节点Java学院

    定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存的状态 类型:行为类 类图: 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态.比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回.这时我们便可以使用备忘录模式来实现. 备忘录模式的结构 发起人:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和

  • Java设计模式之迭代器模式_动力节点Java学院整理

    定义:提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节. 类型:行为类模式 类图: 如果要问Java中使用最多的一种模式,答案不是单例模式,也不是工厂模式,更不是策略模式,而是迭代器模式,先来看一段代码吧: public static void print(Collection coll){ Iterator it = coll.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out

  • Java设计模式之解释器模式_动力节点Java学院整理

    定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 类型:行为类模式 类图: 解释器模式是一个比较少用的模式,本人之前也没有用过这个模式.下面我们就来一起看一下解释器模式. 解释器模式的结构 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作.具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器Nonterm

  • Java设计模式之策略模式_动力节点Java学院整理

    定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过的行为类模式中,有一种模式也是关注对算法的封装--模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是封装到了封装类Context中

  • Java设计模式之代理模式_动力节点Java学院整理

    引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

  • Java设计模式之命令模式_动力节点Java学院整理

    定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 类型:行为类模式 类图: 命令模式的结构 顾名思义,命令模式就是对命令的封装,首先来看一下命令模式类图中的基本结构: Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令. ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现. Client类:最终的客户端调用类.

  • 设计模式之原型模式_动力节点Java学院整理

    定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 类型:创建类模式 类图: 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype.Prototype类需要具备以下两个条件: 实现Cloneable接口.在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法.在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedExcepti

  • Java异常继承结构解析_动力节点Java学院整理

    Java异常类层次结构图: 异常的英文单词是exception,字面翻译就是"意外.例外"的意思,也就是非正常情况.事实上,异常本质上是程序上的错误,包括程序逻辑错误和系统错误.比如使用空的引用.数组下标越界.内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图.错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误,在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,并且运行期间的错误往往是难以预料的.假若程序在运行期间出现了错误

  • 深入理解Java中的final关键字_动力节点Java学院整理

    Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使用final关键字的实例.final经常和static一起使用来声明常量,你也会看到final是如何改善应用性能的. final关键字的含义? final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如

  • Java Date类常用示例_动力节点Java学院整理

    Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单介绍一下Date类的使用. 1.使用Date类代表当前系统时间 Date d = new Date(); System.out.println(d); 使用Date类的默认构造方法创建出的对象就代表当前时间,由于Date类覆盖了toString方法,所以可以直接输出Date类型的对象,显示的结果如下: Sun Ma

随机推荐