首页 > 其他分享 >设计模式之备忘录(Memento)

设计模式之备忘录(Memento)

时间:2023-05-27 15:44:59浏览次数:39  
标签:Originator 备忘录 state memento 设计模式 public Memento

概述

备忘录模式(Memento Pattern),是行为型模式设计模式之一,该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态。备忘录模式实现的方式需要保证被保存的对象状态不能被对象从外部访问,目的是为了保护被保存的这些对象状态的完整性以及内部实现不向外暴露,本篇博客,我们就来一起学习备忘录模式。

使用场景

  • 需要保存一个对象在某一个时刻的状态或部分状态;
  • 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以简洁访问其内部状态。

UML

  备忘录模式UML

Originator: 负责创建一个备忘录,可以记录、恢复自身的内部状态,同时 Originator 还可以根据需要决定 Memento 存储自身的哪些内部状态。

Memento:备忘录角色,用于存储 Originator 的内部状态,并且可以防止 Originator 以外的对象访问 Memento。

CareTaker:负责存储备忘录,不能对备忘录的内容进行操作和访问,只能够将备忘录传递给其他对象。

白箱备忘录模式

Java中,实现“宽”和“窄”两个接口并不容易,如果暂时忽略两个接口的区别,仅为备忘录角色提供一个宽接口的话,备忘录的内部存储状态就对所有对象公开,这就是“白箱实现”。
“白箱”实现破坏了封装性,但是通过程序员自律,可以方便地实现备忘录模式。

package com.dsguo.memento;

public 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;
    }
}
package com.dsguo.memento;

public class Originator {

    private String state;

    /**
     * 工厂方法,返回一个新的备忘录对象
     * @return
     */
    public Memento createMemento() {
        return new Memento(state);
    }


    /**
     * 将发起人恢复到备忘录对象所记载的状态
     * @param memento
     */
    public void restoreMemento(Memento memento) {
        this.state = memento.getState();
    }

    public String getState() {
        System.out.println("当前状态:" + state);
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}
package com.dsguo.memento;

public class Caretaker {

    private Memento memento;

    public Memento retrieveMemento() {
        return this.memento;
    }

    public void saveMemento(Memento memento) {
        this.memento = memento;
    }
}
package com.dsguo.memento;

public class Client {

    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        //改变发起人的状态
        originator.setState("on");
        originator.getState();

        //创建备忘录对象,并将发起人对象的状态存储起来
        caretaker.saveMemento(originator.createMemento());

        originator.setState("off");
        originator.getState();


        //恢复发起人对象的状态
        originator.restoreMemento(caretaker.retrieveMemento());
        originator.getState();
    }
}

运行结果

当前状态:on
当前状态:off
当前状态:on

黑箱备忘录模式

黑箱备忘录模式相比白箱备忘录模式有如下区别:
  • 将Memento设成Originator类的内部类
  • 将Memento的方法全部设成私有方法,这样只有它自己和发起人Originator可以调用;
  • 在外部提供一个标识接口MementoIF给Caretaker以及其他对象,标识接口MementoIF没有提供任何方法,因此对外部来说Memento对象的内容都是不可见的。
package com.dsguo.memento2;

/**
 * 标识接口(窄接口)
 */
public interface MementoIF {

}
package com.dsguo.memento2;

import java.util.Vector;

public class Originator {

    private Vector<Object> states;
    private int index;

    public Originator() {
        states = new Vector<Object>();
        index = 0;
    }

    /**
     * 工厂方法,返回一个新的备忘录对象
     * @return
     */
    public MementoIF createMemento() {
        return new Memento(this.states, index);
    }

    /**
     * 将发起人恢复到备忘录对象所记载的状态
     * @param memento
     */
    public void restoreMemento(MementoIF memento) {
        states = ((Memento)memento).getStates();
        index = ((Memento)memento).getIndex();
    }

    /**
     * 状态的复制方法
     * @param state
     */
    public void setState(Object state) {
        this.states.addElement(state);
        index++;
    }

    /**
     * 辅助方法,打印出所有状态
     */
    public void printStates() {
        System.out.println("total number of states:" + index);
        for (Object o : states) {
            System.out.println(o.toString());
        }
    }

    protected class Memento implements MementoIF {

        private Vector<Object> saveStates;
        private int saveIndex;

        /**
         * states一定是Vector<Object类型的变量,复制后也一定是Vector<Object的变量
         * @param states
         * @param index
         */
        private Memento(Vector<Object> states, int index) {
            //保存客户端传来的状态对象的拷贝,否则客户端的修改会影响到保存的状态。
            saveStates = (Vector<Object>)states.clone();
            saveIndex = index;
        }

        private Vector<Object> getStates() {
            return saveStates;
        }

        private int getIndex() {
            return saveIndex;
        }
    }
}

package com.dsguo.memento2;

import java.util.Vector;

public class Caretaker {
    private Originator o;
    private Vector<MementoIF> mementos = new Vector<MementoIF>();
    private int currentIndex;

    public Caretaker(Originator o) {
        this.o = o;
        currentIndex = 0;
    }

    /**
     * 创建一个新的检查点
     */
    public void createMemento() {
        mementos.add(o.createMemento());
        currentIndex++;
    }

    /**
     * 将发起人恢复到某个检查点
     * @param index
     */
    public void restoreMemento(int index) {
        o.restoreMemento(mementos.elementAt(index));
    }

    /**
     * 删除某个检查点
     * @param index
     */
    public void removeMemento(int index) {
        mementos.removeElementAt(index);
    }

}
package com.dsguo.memento2;

public class Client {

   public static void main(String[] args) {
       Originator originator = new Originator();
       Caretaker caretaker = new Caretaker(originator);

       originator.setState("state0");
       caretaker.createMemento();
       originator.setState("state1");
       caretaker.createMemento();
       originator.setState("state2");
       caretaker.createMemento();

       //打印出所有状态
       originator.printStates();
       System.out.println("restoring to 3");
       caretaker.restoreMemento(1);
       originator.printStates();

   }

}

运行结果:

total number of states:3
state0
state1
state2
restoring to 3
total number of states:2
state0
state1

跟例子1相比,负责人角色除了负责保存状态之外,还负责发起人状态的恢复,功能增强了。

总结

黑箱”备忘录的实现中,将Memento类做成Originator的内部类,并将其方法全部设置成private,其实这样一般来说就已经足够了,不需要再使用窄接口MementoIF。因为这样做的话外部拿到Memento类的实例,由于其方法都是private的,所以该方法只有Originator类可以调用,其它类是调用不了的,也就无法修改其中的内容。



作者:ikonan
链接:https://www.jianshu.com/p/0d84adfda53e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:Originator,备忘录,state,memento,设计模式,public,Memento
From: https://www.cnblogs.com/20201411-hzb/p/17436838.html

相关文章

  • 设计模式-观察者模式(Observer)
    一、 观察者(Observer)模式观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通......
  • 设计模式-行为型设计模式
    责任链模式定义为请求创建一个接收此次请求的链适用场景一个请求的处理需要多个对象当中的一个或几个协作处理优点请求的发送者和接收者(请求的处理)解耦责任链可以动态组合缺点责任链太长或者处理时间过长,影响性能责任链有可能过多/**处理者--或者Approver*@author......
  • Simple Factory Pattern 简单工厂模式简介与 C# 示例【创建型】【设计模式来了】
     〇、简介1、什么是简单工厂模式?一句话解释:  客户类和工厂类严格分工,客户类只需知道怎么用,处理逻辑交给工厂类。简单工厂模式(SimpleFactoryPattern)是日常开发中常用的设计模式。其是一种简单的创建型模式,它通过一个工厂类来创建对象,客户端只需要知道如何使用工厂类,而不需......
  • 如何在win10桌面添加备忘录?电脑桌面添加备忘录方法
    Win10系统电脑在国内的办公场景中普及率是非常高的,绝大多数从事普通工作的职场人士都会使用win10系统电脑来办公。不过有不少上班族表示,自己在使用电脑办公时,如果想要随手记录一些工作注意事项、工作常规流程、待办的工作任务等,只能够打开手机在备忘录中记录这些事情,简直太不方便......
  • Java设计模式-策略模式
    简介在软件开发中,设计模式是为了解决常见问题而提供的一套可重用的解决方案。策略模式(StrategyPattern)是其中一种常见的设计模式,它属于行为型模式。该模式的核心思想是将不同的算法封装成独立的策略类,使得它们可以相互替换,而不影响客户端的使用。策略模式与其他设计模式有一些......
  • javascript设计模式-享元
    这是一种优化性能代码的模式,最适合解决因创建大量类似对象而累及性能的问题。对于那些可能一连几天也不会重新加载的大型应用系统非常有用。它用于减少应用程序所需要数量,通过将对象内部划分为内在数据和外在数据两类来实现。管理享元外在数据有许多方法:1、数据库;2、组合模式(利用......
  • 《设计模式之禅》Multition_Pattern--多例模式
    多例模式嘿,咱们书接上回。单例模式就是每次只能有一个实例,那么多例模式就是可以有多个实例对象。那在中国历史上有没有这种事情发生过呢,嘿,你别说,还真有,就出现在明朝,那三国期间的算不算,不算,各自称帝,各有各的地盘,国号不同。大家还记得那首诗《石灰吟》吗?作者是谁?于谦,他是被谁杀死的?明......
  • 设计模式-软件设计原则
    开闭原则定义:一个软件实体如类,模块和函数应该对扩展开放,对修改关闭用抽象构建框架,用实现扩展细节优点:提高软件系统可复用性和可维护性依赖倒置原则定义:高层模块不应该依赖底层模块,二者都应该依赖其抽象抽象不应该依赖细节,细节应该依赖抽象针对接口编程,不要针对实现编程优......
  • Singleton 单例模式简介与 C# 示例【创建型】【设计模式来了】
     〇、简介1、什么是单例模式?一句话解释:  单一的类,只能自己来创建唯一的一个对象。单例模式(SingletonPattern)是日常开发中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时......
  • 设计模式整理
    责任链模式顾名思义,责任链模式(ChainofResponsibilityPattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该......