备忘录模式(二十二)

相信自己,请一定要相信自己

上一章简单介绍了中介者模式(二十一), 如果没有看过, 请观看上一章

一. 备忘录模式

引用 菜鸟教程里面备忘录模式介绍: https://www.runoob.com/design-pattern/memento-pattern.html

备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。

备忘录模式属于行为型模式。

一.一 介绍

意图: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

主要解决: 所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,
这样可以在以后将对象恢复到原先保存的状态。

何时使用: 很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,
能够恢复到他原先的状态,使得他有"后悔药"可吃。

如何解决: 通过一个备忘录类专门存储对象状态。

关键代码: 客户不与备忘录类耦合,与备忘录管理类耦合。

应用实例: 1、后悔药。 2、打游戏时的存档。 3、Windows 里的 ctrl + z。 4、IE 中的后退。 5、数据库的事务管理。

优点:
1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
2、实现了信息的封装,使得用户不需要关心状态的保存细节。

缺点: 消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

使用场景: 1、需要保存/恢复数据的相关状态场景。 2、提供一个可回滚的操作。

注意事项: 1、为了符合迪米特原则,还要增加一个管理备忘录的类。 2、为了节约内存,可使用原型模式+备忘录模式。


组成角色 具体 关系
要保存的对象(originator) GameRole 对象(需要保存状态的对象)
备忘录对象(Memento) Memento 备忘录对象,负责保存好记录,即Originator 内部状态
守护者对象(Caretaker) Caretaker 守护者对象,负责保存多个备忘录对象, 使用集合管理,提高效率

image-20230615192235669

二. 备忘录实例

二.一 要保存的对象 GameRole

@Data
@Slf4j
public class GameRole {
    
    
    /**
     攻击力,防御力,血量
     */
    private int vit;
    private int def;
    private int blood;
    private String name;
    private String field1;

    public Memento createMemento() {
    
    
        return Memento.builder()
                .vit(vit)
                .def(def)
                .blood(blood)
                .build();
    }

    // 恢复状态
    public void recoverFromMemento( Memento memento) {
    
    
        this.vit = memento.getVit();
        this.def = memento.getDef();
        this.blood = memento.getBlood();
    }

    public void display() {
    
    
        log.info("当前 攻击力是: {}, 防御力: {},血量:{}",vit,def,blood);
    }
}

二.二 备记录对象 Memento

@Data
@Builder
public class Memento {
    
    
    /**
     攻击力,防御力,血量
     */
    private int vit;
    private int def;
    private int blood;
}

二.三 守护者对象 Caretaker

public class Caretaker {
    
    

    private Map<String,Memento> statusMap = new HashMap<>();


    // 根据 标识获取信息

    public Memento getByStatus (String status) {
    
    
        return statusMap.get(status);
    }

    public void saveStatus (String status, Memento memento) {
    
    
        statusMap.put(status,memento);
    }


}

二.四 客户端调用

@Test
    public void oneTest() {
    
    

        GameRole gameRole = new GameRole();
        gameRole.setVit(0);
        gameRole.setDef(0);
        gameRole.setBlood(100);

        log.info(">>> 打之前的数据是: ");
        gameRole.display();


        Memento memento = gameRole.createMemento();
        Caretaker caretaker = new Caretaker();
        caretaker.saveStatus("start",memento);


        gameRole.setVit(20);
        gameRole.setDef(20);
        gameRole.setBlood(50);
        log.info(">>> 打一半的数据是: ");
        gameRole.display();
        // 存个档
        caretaker.saveStatus("middle",gameRole.createMemento());
        // 回退到开始的版本

        gameRole.recoverFromMemento(caretaker.getByStatus("start"));

        gameRole.setVit(20);
        gameRole.setDef(0);
        gameRole.setBlood(0);
        log.info(">>> 最后的数据是: ");
        gameRole.display();
        // 存个档
        caretaker.saveStatus("end",gameRole.createMemento());



        log.info(">>> 回退到开始的版本: ");
        gameRole.display();
    }

image-20230615192514120


本章节的代码放置在 github 上:


https://github.com/yuejianli/DesignPattern/tree/develop/Memento


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

猜你喜欢

转载自blog.csdn.net/yjltx1234csdn/article/details/131234497