设计模式-备忘录模式

时间:2022-07-25
本文章向大家介绍设计模式-备忘录模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

背景

美国大片好多超级英雄的角色,一个人从头干到尾,还毫发无损,真的是大家很崇拜的对象,而超级英雄平常也是普通人状态,等到世界末日或者说变身的时候才变成超级牛逼的一种状态,干完架又恢复成普通人,这里其实跟备忘录模式有点像,普通状态和超级英雄状态。

备忘录模式是什么?

备忘录模式(Memento Pattern),属于行为模式,定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便恢复到原先保存的状态。

角色

Originator(发起人角色):负责创建、记录、恢复自身内部状态或数据。

Mement(备忘录角色):负责存储Originator的内部状态或数据,并且可以提供Originator的内部状态或数据。

Caretaker(备忘录管理员角色):负责管理备忘录,只负责将备忘录内容进行传递;

备忘录模式可以干嘛?

备忘录将当前的对象,通过一个存储容器,将该对象或对象的一些内部状态信息,存储一份,然后通过该备份,当原对象需要恢复的时候通过备忘录管理员角色,对原有的备忘录数据进行恢复。该模式主要用于恢复和保存对象的状态或对象。

优点:

遵循迪米特法则:由于角色的备份信息由备忘录管理员角色,只负责管理,而不能直接去修改备忘录的信息,并且该备忘录最终操作也由发起人来决定是否恢复。

恢复机制:提供了一套,当用户需要的时候将内部状态或信息保存、恢复,并且用户不需要关心具体细节。

缺点:

开销大:由于一个备份就需要在内存中存放一个对象,如果是多对象和多状态的场景,可能内存开销就很大了。

个人理解:

备忘录就像我们平常手机里面的通讯录,为了防止丢失记录一份,需要的时候直接调出来就拨打了,也可以这么理解为电影里面的超级英雄角色,关键的时候变身超级英雄等到干完活后,恢复成普通人。

备忘录模式类图

源码下载:https://gitee.com/hong99/design-model/issues/I1IMES实现代码

/**
 * @Auther: csh
 * @Date: 2020/6/10 14:39
 * @Description:人 (Originator)
 */
public class Person {
    private String status;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public void changeStatus(){
        this.status="变身超人";
    }

    //保存状态
    public Memento saveStateToMemento(){
        return new Memento(status);
    }

    //通过记录获取状态
    public void getStatusFromMemento(Memento memento){
        if(null!=memento){
            this.status = memento.getState();
        }else{
            System.out.println("没有状态恢复!");
        }
    }
}
/**
 * @Auther: csh
 * @Date: 2020/6/10 14:41
 * @Description:Mement(备忘录角色)
 */
public class Memento {
    private String state;

    public Memento(String state){
        this.state = state;
    }

    public String getState(){
        return state;
    }
}
/**
 * @Auther: csh
 * @Date: 2020/6/10 14:46
 * @Description:Caretaker(备忘录管理员角色)
 */
public class CareTaker {
    //存储备份的列表
    private List<Memento> mementoList = new ArrayList <Memento>();
    //添加
    public void add(Memento memento) {
        if(null!=memento){
            this.mementoList.add(memento);
        }
    }

    //获取方式
    public Memento getToMemento(Memento memento){
        for (Memento mo : mementoList) {
            if(mo.getState().equals(memento.getState())){
                return mo;
            }
        }
        return null;
    }

    //获取
    public Memento get(int index){
        return mementoList.get(index);
    }
    //删除
    public boolean del(Memento memento){
        if(null!=memento){
            return this.mementoList.remove(memento);
        }
        return false;
    }
}
/**
 * @Auther: csh
 * @Date: 2020/6/10 14:51
 * @Description:
 */
public class Client {
    public static void main(String[] args) {
        CareTaker careTaker = new CareTaker();
        Person person  = new Person();
        person.setStatus("普通人");
        System.out.println("------保存状态--------");
        Memento memento = person.saveStateToMemento();
        careTaker.add(memento);
        System.out.println("变身前状态:"+person.getStatus());
        System.out.println("--------变身--------");
        person.changeStatus();
        System.out.println("拯救世界去了:"+person.getStatus());
        System.out.println("继续恢复平凡人的身份......");
        person.getStatusFromMemento(careTaker.get(0));
        System.out.println("恢复后:"+person.getStatus());
    }
}

结果

------保存状态--------
变身前状态:普通人
--------变身--------
拯救世界去了:变身超人
继续恢复平凡人的身份......
恢复后:普通人

源码下载:https://gitee.com/hong99/design-model/issues/I1IMES最后

备忘录模式在实际日常开发过程中,还是比较常见,有时候还有多状态多备份的需求,甚至有时候会根据时间来保存,这时候的话就可能通过数据库或者一些缓存池来记录,当需要恢复到某个状态或某个时间节点的时候,对其指定恢复。当然如果完全放到缓存中对系统性能有一定影响,特别是那种备份次数特别多的时候,可能会导致内存开销非常高,而GC又回收不到然后就各种超时异常出现,一查发现内存GG了....建议如果是备忘录需要结合业务或者给个过期时间,通过记录后,规定的时候失效,可以放到晚上或者说隔多长时间,要不然可真的可能一直保存该种信息就...

场景

Windows 里的 ctri + z。

IE 中的后退操作

数据库的事务管理