java设计模式-行为型模式-备忘录模式

备忘录模式

备忘录模式,顾名思义为了就是实现一个“备忘”的功能而存在的。官话:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复至原先保存的状态。

三个角色

  • Originator:发起人,就是想要实现备忘功能的角色
  • Memento:备忘类,帮助实现备忘功能的角色,拥有和发起人一样的想要备份的属性,发起人通过备忘录类来恢复之前的数据
  • CareTaker:用来保存备忘类的角色

栗子

有这样一个人,他想要自杀,自杀以后呢,他又后悔了,想复活,用备忘录模式来实现。

  • 定义这个人

拥有“姓名”和“状态”两个属性,想要备份“状态”属性

/**
 * @author river
 * @date 2019-02-25 12:26
 * 人
 */
public class Person {

    private String name;

    private State state;

    /**
     * 创建备忘对象
     * @return
     */
    public StateMemento createMemento() {
        return new StateMemento(this);
    }

    /**
     * 自杀
     */
    public void suicide() {
        this.state = State.DEAD;
        display();
    }

    /**
     * 后悔
     * @param stateMemento
     */
    public void regret(StateMemento stateMemento) {
        this.state = stateMemento.getState();
        display();
    }

    public void display() {
        System.out.println(String.format("我是:%s,我现在状态是:%s", name, state.desc));
    }

    public String getName() {
        return name;
    }

    public State getState() {
        return state;
    }

    public Person(String name, State state) {
        this.name = name;
        this.state = state;
        display();
    }

    public enum State {
        ALIVE("alive", "活着"),
        DEAD("dead", "死了");
        private String name;
        private String desc;

        State(String name, String desc) {
            this.name = name;
            this.desc = desc;
        }
    }
}
  • 定义备忘类

拥有发起人的“状态”属性,备份发起人的状态属性

/**
 * @author river
 * @date 2019-02-25 12:30
 * 状态备忘类
 */
public class StateMemento {

    private Person.State state;

    public StateMemento(Person person) {
        this.state = person.getState();
    }

    public Person.State getState() {
        return state;
    }

    public void setState(Person.State state) {
        this.state = state;
    }
}
  • 备忘类管理类

如果只实现一次的备忘,那么这个类可以省略

/**
 * @author river
 * @date 2019-02-25 12:35
 * 备忘管理类,用来存放备忘类
 */
public class MementoManager {

    private StateMemento stateMemento;

    public MementoManager(StateMemento stateMemento) {
        this.stateMemento = stateMemento;
    }

    public StateMemento getStateMemento() {
        return stateMemento;
    }

    public void setStateMemento(StateMemento stateMemento) {
        this.stateMemento = stateMemento;
    }
}
  • 具体使用
 /**
 * @author river
 * @date 2019-02-25 12:37
 * 主程序
 */
public class Main {

    public static void main(String[] args) {
        Person tom = new Person("Tom", Person.State.ALIVE);
        System.out.println("------------------------------------");
        System.out.println("存档");
        MementoManager mementoManager = new MementoManager(tom.createMemento());
        System.out.println("------------------------------------");
        System.out.println("我现在不想活了,我自杀");
        tom.suicide();
        System.out.println("------------------------------------");
        System.out.println("我现在又后悔了,我想复活");
        tom.regret(mementoManager.getStateMemento());
    }
}
  • 结果如下
我是:Tom,我现在状态是:活着
------------------------------------
存档
------------------------------------
我现在不想活了,我自杀
我是:Tom,我现在状态是:死了
------------------------------------
我现在又后悔了,我想复活
我是:Tom,我现在状态是:活着

总结

优点:提供了一种可以恢复的机制,实现备份的功能
缺点:如果需要备份的属性太多,那么势必要占用更多的内存,每次保存都会多消耗资源

补充

实现多次备份,多次恢复,多次取消恢复

复杂一点的栗子

实现windows下Ctrl+z,Ctrl+y

  • 定义一个操作类

把备忘录类当做操作类的内部类,定义了ctrlZ、ctrlY方法

/**
 * @author river
 * @date 2019-02-25 13:21
 * 操作类
 */
public class Operation {

    private String content;
    private Integer currentStep;

    public Operation(String content) {
        this.content = content;
        this.currentStep = 1;
    }

    public Memento createMemento() {
        return new Memento(this);
    }

    /**
     * 打字
     * @param content
     */
    public void type(String content) {
        this.content += content;
        this.currentStep++;
        display();
    }

    /**
     * 显示
     */
    public void display() {
        System.out.println(String.format("当前操作是第%s步,当前内容是:%s", currentStep, content));
    }

    public void ctrlZ(Memento memento) {
        System.out.println("操作了Ctrl+z");
        this.currentStep = memento.step;
        this.content = memento.context;
        display();
    }

    public void ctrlY(Memento memento) {
        System.out.println("操作了Ctrl+y");
        this.currentStep = memento.step;
        this.content = memento.context;
        display();
    }

    class Memento {
        private String context;
        private Integer step;

        public Memento(Operation operation) {
            this.context = operation.content;
            this.step = operation.currentStep;
        }
    }
}
  • 定义保存备忘录的类

用list来存储备忘录类,记录每一步的操作,设置一个游标cursor,来记录位置,每次undo操作,游标减1后取值,每次redo,游标加1后取值,每次保存save的时候删除掉当前游标后面的元素,然后再保存。

/**
 * @author river
 * @date 2019-02-25 13:33
 * 备忘录类保存类
 */
public class Caretaker {

    private List<Operation.Memento> mementos = new ArrayList<>();
    private Integer cursor;

    public Caretaker(Operation.Memento memento) {
        mementos.add(memento);
        cursor = 0;
    }

    public void save(Operation.Memento memento) {
        if (cursor < mementos.size() - 1) {
            this.mementos = this.mementos.subList(0, cursor + 1);
        }
        this.mementos.add(memento);
        this.cursor++;
    }

    public Operation.Memento undo() {
        if (cursor > 0) {
            cursor--;
        }
        return this.mementos.get(cursor);
    }

    public Operation.Memento redo() {
        if (cursor < mementos.size() - 1) {
            cursor++;
        }
        return mementos.get(cursor);
    }
}
  • 编写测试
/**
 * @author river
 * @date 2019-02-25 13:45
 * 主程序
 */
public class Main {
    public static void main(String[] args) {
        Operation operation = new Operation("我想打一些字");
        Caretaker caretaker = new Caretaker(operation.createMemento());
        operation.display();

        operation.type(",再打几个字");
        caretaker.save(operation.createMemento());

        operation.type(",还打几个字");
        caretaker.save(operation.createMemento());

        operation.ctrlZ(caretaker.undo());

        operation.type(",我又打了几个字");
        caretaker.save(operation.createMemento());

        operation.type(",最后再打几个字");
        caretaker.save(operation.createMemento());

        operation.ctrlZ(caretaker.undo());
        operation.ctrlY(caretaker.redo());
        operation.ctrlY(caretaker.redo());
        operation.ctrlZ(caretaker.undo());
        operation.ctrlZ(caretaker.undo());
        operation.ctrlZ(caretaker.undo());
        operation.ctrlZ(caretaker.undo());
    }
}
  • 运行结果
当前操作是第1步,当前内容是:我想打一些字
当前操作是第2步,当前内容是:我想打一些字,再打几个字
当前操作是第3步,当前内容是:我想打一些字,再打几个字,还打几个字
操作了Ctrl+z
当前操作是第2步,当前内容是:我想打一些字,再打几个字
当前操作是第3步,当前内容是:我想打一些字,再打几个字,我又打了几个字
当前操作是第4步,当前内容是:我想打一些字,再打几个字,我又打了几个字,最后再打几个字
操作了Ctrl+z
当前操作是第3步,当前内容是:我想打一些字,再打几个字,我又打了几个字
操作了Ctrl+y
当前操作是第4步,当前内容是:我想打一些字,再打几个字,我又打了几个字,最后再打几个字
操作了Ctrl+y
当前操作是第4步,当前内容是:我想打一些字,再打几个字,我又打了几个字,最后再打几个字
操作了Ctrl+z
当前操作是第3步,当前内容是:我想打一些字,再打几个字,我又打了几个字
操作了Ctrl+z
当前操作是第2步,当前内容是:我想打一些字,再打几个字
操作了Ctrl+z
当前操作是第1步,当前内容是:我想打一些字
操作了Ctrl+z
当前操作是第1步,当前内容是:我想打一些字

回到主目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值