浅谈设计模式 - 备忘录模式(十五)

简介: 浅谈设计模式 - 备忘录模式(十五)

前言


备忘录这个模式用的比较少,基本学完就可以忘记的一个模式,但是应用的情况还是不少,同时这个模式几乎“人手必备”,那就是典型的ctrl+z这个功能就可以看作备忘录的典型案例,我们的游戏存档也可以看作是一种备忘录的变形。


定义


备忘录模式重点在于记录住对象的状态,可以让对象的状态回到上一次操作的时候,同时可以保证不破坏封装性的前提下存在于其他的对象,这个模式需要注意的一个点是为了管理备忘的类,需要一个“辅助类”来进行备忘内容的统一管理,就好比我们的游戏的存档和读档一样。


应用场景


  1. 游戏的存档
  2. 恢复上一次状态
  3. 文字撤销
  4. 还原


优缺点:


  1. 不破坏对象的封装性保存对象的状态,可以让对象回到过去定义的任何一种状态。
  2. 用户不需要关系备忘的内容以及如何备忘,只需要关注备忘的数据即可。
  3. 备忘的数据过多会造成卡顿,并且有可能存在备忘记录丢失的可能性。


结构图:



备忘录模式主要分为三个点,第一:需要定义和备忘的内容有关的对外接口,并且将请求转发给具体的备忘器,然后备忘器备忘数据存储到具体的备忘实现对象来保存对象的状态,第二:定义备忘录存储接口传递对象的状态,记录当前的工作数据,第三需要使用具体的记录器恢复器对象来恢复具体的对象数据。

了解基本的设计对象之后下面来看下具体的实现结构图,这种模式有两种实现的结构方式,一种是嵌套类的结构,另一种是使用中间接口委托的形式进行处理,但是不管是嵌套结构还是中间接口委托的形式,基本都包含了下面的接口:

Memento(备忘录):包含了要被恢复的对象的状态,是快照的具体存储位置。

Originator(原发器):创建并在 Memento 对象中存储状态,可以看作是需要被快照的对象,通常包含某些状态数据。

Caretake(恢复器):负责从 Memento 中恢复对象的状态,可以看作是一个记录提取器或者说恢复器。


嵌套结构


嵌套结构的结构图如下所示,嵌套的结构下通常会把原发器嵌入到备忘录的接口里面,在部分的时候通过备忘录把数据进行恢复或者存储,恢复器负责对于原发器的状态进行还原的操作:


网络异常,图片无法展示
|


中间接口结构



中间接口结构针对一些不能使用嵌套类的情况,这时候我们只能委托给子类完成备份数据的处理,当然这样也有一种灵活性,就是备份的方式可以多样化。


网络异常,图片无法展示
|


案例代码


下面我们来看下上面的结构图的相关代码,由于这里使用的是java代码,所以我们直接使用嵌套类的形式完成:

Originator(原发器):创建并在 Memento 对象中存储状态,可以看作是需要被快照的对象,通常包含某些状态数据。


public class Originator {
    private String state;
    public Originator() {
    }
    public Originator(Memento memento) {
        memento = new Memento(state);
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
}


Memento(备忘录):包含了要被恢复的对象的状态,是快照的具体存储位置。


public class Memento {
    /**
     * 需要被备份的状态
     */
    private String state;
    public Memento(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
}


Caretake(恢复器):负责从 Memento 中恢复对象的状态,可以看作是一个记录提取器或者说恢复器。


public class CareTaker {
    private Memento memento;
    public CareTaker(Memento memento) {
        this.memento = memento;
    }
    public Memento getMemento() {
        return memento;
    }
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}


Client:最终的执行客户端,通过调用CareTaker进行将数据的状态进行还原:


public class Client {
    private Originator originator;
    public Client(Originator originator) {
        this.originator = originator;
    }
    /**
     * 恢复记录的状态
     */
    public void restore(CareTaker careTaker) {
        originator.setState(Optional.ofNullable(careTaker)
                .map(CareTaker::getMemento)
                .map(Memento::getState)
                .orElse("off"));
    }
}


最后是单元测试:


public class Main {
    public static void main(String[] args) {
        Originator originator = new Originator();
        originator.setState("on");
        System.out.println("备份状态"+ originator.getState());
        Memento memento = new Memento(originator.getState());
        CareTaker careTaker = new CareTaker(memento);
        //修改状态
        originator.setState("test");
        System.out.println("修改状态"+ originator.getState());
        Client client = new Client(originator);
        client.restore(careTaker);
        System.out.println("还原状态"+ originator.getState());
    }/*运行结果:
        备份状态on
        修改状态test
        还原状态on
    */
}


实际案例


不管是操作系统还是文本编辑,备忘和撤销的功能是必不可少的,所以我们用文本编辑器来讲述备忘录模式。最常见的情况是我们写好文章写到一半的时候关闭软件下次进入依然有原来的数据。这里我们使用“特殊方法”代替ctrl+s来进行数据的备份操作。

代码的内容和案例内容类似,只不过由于使用了对象需要注意对象的潜拷贝和深拷贝的问题。

首先我们建立文本对象:


public class Text {
    /**
     * 文本信息
     */
    private String info;
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}


下面是一个文本编辑器:


public class TextEditor {
    private Text text;
    public TextEditor(Text text) {
        this.text = text;
    }
    public void write(String info){
        text.setInfo(info);
    }
    public Text getText() {
        return text;
    }
    public void setText(Text text) {
        this.text = text;
    }
}


备忘录需要注意备份对象需要使用深拷贝


public class Memento {
    private Text text;
    public Text getText() {
        return text;
    }
    public void setText(Text text) {
        String info = text.getInfo();
        Text newText = new Text();
        newText.setInfo(info);
        this.text = newText;
    }
}


恢复器,最后要使用恢复器进行数据的恢复操作


public class CareTaker {
    private Memento memento;
    public CareTaker(Memento memento) {
        this.memento = memento;
    }
    /**
     * 恢复记录的状态
     */
    public void restore(TextEditor textEditor) {
        textEditor.getText().setInfo(memento.getText().getInfo());
    }
    public Memento getMemento() {
        return memento;
    }
    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}


最后是测试代码:


public class Main {
    public static void main(String[] args) {
        Text text = new Text();
        TextEditor textEditor = new TextEditor(text);
        textEditor.write("d111111");
        Memento memento = new Memento();
        memento.setText(text);
        CareTaker careTaker = new CareTaker(memento);
        textEditor.write("66666");
        careTaker.restore(textEditor);
        System.out.println(careTaker.getMemento().getText().getInfo());
    }/*运行结果:
        浅拷贝:66666
        深拷贝:d111111
    */
}


总结



这个设计模式用的真的并不算很多,所以简单过一下即可。


写在最后



算是比较有意思的设计模式。

相关文章
|
5月前
|
设计模式 存储 Java
浅谈设计模式 - 备忘录模式(十五)
浅谈设计模式 - 备忘录模式(十五)
44 0
|
5月前
|
设计模式 存储 Java
Java设计模式【十九】:备忘录模式
Java设计模式【十九】:备忘录模式
37 0
|
5月前
|
设计模式 前端开发
浅谈设计模式 - 中介者模式(十六)
浅谈设计模式 - 中介者模式(十六)
59 0
|
5月前
|
设计模式 Java 测试技术
浅谈设计模式 - 责任链模式(十四)
浅谈设计模式 - 责任链模式(十四)
63 0
|
11月前
|
设计模式 C++
二十三种设计模式:状态模式
状态模式,就是把所有的状态抽象成一个个具体的类,然后继承一个抽象状态类,在每一个状态类内封装对应状态的行为,符合开放封闭原则,当增加新的状态或减少状态时,只需修改关联的类即可。很适合多分支行为方法的处理,这里的多分支,当然是状态比较多的情况下,如果只有小于4个状态,个人认为还是分支处理简单些。
51 0
|
设计模式 前端开发 UED
前端实现设计模式之备忘录模式
在前端开发中,我们经常需要实现撤销和恢复功能,或者保存用户操作的历史记录。备忘录模式是一种行为型设计模式,通过保存对象的内部状态并在需要时进行恢复,实现了撤销和恢复功能。本文将介绍备忘录模式在前端开发中的应用,并提供具体的代码示例和解读。
117 0
|
设计模式
设计模式轻松学【十五】状态模式
在生活中,人的情绪往往都在变化,有高兴的时候和伤心的时候,不同的情绪有不同的行为,比如你开心的时候,会去大吃一顿,伤心的时候会出去唱K。外界也会影响我们的情绪,唱K之后你就变得开心了。 这个情绪的变化我们可以看成一个对象的状态变化,状态改变时会有不同的操作。对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else 语句来做状态判断,再进行不同情况的处理。但当对象的状态很多时,程序会变得很复杂。这很像策略模式、但他们有着本质的区别。
71 0
设计模式轻松学【十五】状态模式
|
设计模式 算法 编译器
设计模式(二十四) 访问者模式
访问者模式提供了一种方法,将算法和数据结构分离。假设我们需要对一个数据结构进行不同的操作,就可以考虑使用访问者模式。访问者模式的要点在于,需要一个访问者接口,提供了一些重载方法来访问具体对象。
748 0
|
设计模式 缓存 前端开发
《前端实战总结》之设计模式的应用——备忘录模式
备忘录模式简单的说就是在不破坏已有逻辑的前提下,将日后需要获取的数据在第一次保存下来以免造成重复且低效的操作。该设计模式最主要的任务就是对现有数据或者状态做缓存,为将来某个时刻使用或者恢复做准备。
126 0
|
设计模式 C#
设计模式(十五)之观察者模式
观察者模式(Observer Pattern)是设计模式中行为模式的一种,它解决了上述具有一对多依赖关系的对象的重用问题。此模式的参与者分为两大类,一类是被观察的目标,另一类是观察该目标的观察者们。 正因为该模式是基于“一对多”的关系,所以该模式一般是应用于由一个目标对象和N个观察者对象组成(当然也可以扩展为有多个目标对象,但我们现在只讨论前者)的场合。 当目标对象的状态发生改变或做出某种行为时,正在观察该目标对象的观察者们将自动地、连锁地作出相应的响应行为。
116 0
设计模式(十五)之观察者模式