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
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值