美文网首页
备忘录模式

备忘录模式

作者: 忘净空 | 来源:发表于2016-08-18 17:05 被阅读1029次

模式定义:

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

模式场景

  1. 录入大批人员资料的时候。正在录入当前人资料时,发现上一个人录错了,此时需要恢复到上一个人的资料,进行修改。
  1. Word编辑时,忽然断电或电脑死机,再打开时,可以看到Word提示你恢复到以前的文档。

模式结构

模式结构
  1. Memento:备忘录。主要用来存储原发器对象的内部状态,但是具体需要存储哪些数据是由原发器对象来决定的。另外备忘录应该只能由原发器对象来访问它内部的数据,原发器外部的对象不应该能访问到备忘录对象的内部数据。

  2. Originator:原发器。使用备忘录来保存某个时刻原发器自身的状态,也可以使用备忘录来恢复内部状态。

  1. Caretaker:备忘录管理者,或者称为备忘录负责人。主要负责保存备忘录对象,但是不能对备忘录对象的内容进行操作或检查。

代码实现

UML图

源码

public interface FlowAMockMemento {
}

public class FlowAMock {
    private String flowName;
    private int tempResult;
    private String tempState;

    public FlowAMock(String flowName) {
        this.flowName = flowName;
    }

    public void runPhaseOne(){
        tempResult = 3;
        tempState = "phaseOne";
    }
    public void schema1(){
        this.tempState += ",Schema1";
        System.out.println(this.tempState+":now run " + tempResult);
        this.tempResult += 11;
    }

    public void schema2(){
        this.tempState += ",Schema2";
        System.out.println(this.tempState+":now run " + tempResult);
        this.tempResult += 22;
    }

    public FlowAMockMemento createMemento(){
        return new MementoImpl(this.tempResult,this.tempState);
    }

    public void setMemento(FlowAMockMemento memento){
        MementoImpl mementoImpl = (MementoImpl) memento;
        this.tempResult = mementoImpl.getTempResult();
        this.tempState = mementoImpl.getTempState();
    }

    /**
     * 真正的备忘录对象,实现备忘录窄接口
     * 实现成为私有内部类
     */
    private static class MementoImpl implements FlowAMockMemento{
        @Getter
        private int tempResult;
        @Getter
        private String tempState;

        public MementoImpl(int tempResult, String tempState) {
            this.tempResult = tempResult;
            this.tempState = tempState;
        }
    }
}

@Data
public class FlowAMementoCareTaker{

    private FlowAMockMemento memento;
}

public class Client {
    public static void main(String[] args) {
        FlowAMock mock = new FlowAMock("testFlow");
        mock.runPhaseOne();

        FlowAMementoCareTaker careTaker = new FlowAMementoCareTaker();
        FlowAMockMemento memento = mock.createMemento();
        careTaker.setMemento(memento);

        mock.schema1();
        mock.setMemento(memento);
        mock.schema2();
    }
}

模式的优缺点

模式的优点

  1. 更好的封装性

    备忘录模式通过使用备忘录对象,来封装原发器对象的内部状态,虽然这个对象是保存在原发器对象的外部,但是由于备忘录对象的窄接口并不提供任何方法,这样有效的保证了对原发器对象内部状态的封装,不把原发器对象的内部实现细节暴露给外部。

  2. 简化了原发器

    备忘录模式中,备忘录对象被保存到原发器对象之外,让客户来管理他们请求的状态,从而让原发器对象得到简化。

  3. 窄接口和宽接口

模式的缺点

  1. 可能会导致高开销

    备忘录模式基本的功能,就是对备忘录对象的存储和恢复,它的基本实现方式就是缓存备忘录对象。这样一来,如果需要缓存的数据量很大,或者是特别频繁的创建备忘录对象,开销是很大的。

思考

模式本质:保存和恢复内部状态

开发中的应用场景:

  1. 棋类游戏,悔棋

  2. 普通软件,撤销操作

  3. 数据库软件中的,事务管理的,回滚操作

  4. Photoshop软件

相关模式

  1. 备忘录模式和命令模式
    这两个模式可以组合使用。

命令模式实现中,在实现命令的撤销和重做的时候,可以使用备忘录模式,在命令操作的时候记录下操作前后的状态,然后在命令撤销和重做的时候,直接使用相应的备忘录对象来恢复状态就可以了。
在这种撤销的执行顺序和重做执行顺序可控的情况下,备忘录对象还可以采用增量式记录的方式,可以减少缓存的数据量。

  1. 备忘录模式和原型模式
    这两个模式可以组合使用。

在原发器对象创建备忘录对象的时候,如果原发器对象中全部或者大部分的状态都需要保存,一个简洁的方式就是直接克隆一个原发器对象。也就是说,这个时候备忘录对象里面存放的是一个原发器对象的实例。

相关文章

网友评论

      本文标题:备忘录模式

      本文链接:https://www.haomeiwen.com/subject/idivsttx.html