设计模式之备忘录模式

新的游戏功能

之前公司的游戏小明通过原型模式完成了游戏中的小怪对象,现在公司游戏有一个需求,需要定期保存游戏的进度,并且用户可以恢复到保存的进度

小明对于这个功能无从下手,于是请教了主管,主管让小明去了解一下备忘录模式,使用备忘录模式就可以完成这个功能,于是小明去搜集了一下备忘录的资料,然后将这个模式迅速掌握并应用到了新的功能上

定义

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态

备忘录模式

角色

  • 发起人
  • 备忘录
  • 管理角色

用备忘录实现功能

通过备忘录模式的类图和角色,我们来实现一下我们的程序。首先,我们要定义我们的备忘录类,他记录了具体的状态

public interface IMemento {
}
public class Memento implements IMemento {

    private int progress;

    public Memento(int progress) {
        this.progress = progress;
    }

    public int getProgress() {
        return progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
    }
}

我们需要保存的是游戏的进度,所以我们游戏进度类是发起人,它来定义游戏进度类中哪些状态需要保存

游戏状态类,也就是我们的发起者:

public class Originator {

    int progress;

    public Originator() {
    }

    public int getProgress() {
        return progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
    }

    public Memento createMemento() {
        return new Memento(this.progress);
    }

    public void restoreMemento(IMemento memento) {
        this.setProgress(((Memento) memento).getProgress());
    }

}

另外,我们还需要一个类来管理我们这些状态,可以根据实际需求来指定这个管理角色的管理形式,我们使用一个Map来管理,这样可以保存多个状态

public class Caretaker {

    Map<String, IMemento> mementos;

    public Caretaker() {
        mementos = new HashMap<>();
    }

    public IMemento getMemento(String name) {
        return mementos.get(name);
    }

    public void addMemento(String name, Memento memento) {
        this.mementos.put(name, memento);
    }
}

现在我们来使用这个备忘录,帮助我们完成状态的恢复

public class Client {
    public static void main(String[] args) {

        Originator originator = new Originator();
        originator.setProgress(1);
        System.out.println("当前进度 " + originator.getProgress());

        Caretaker caretaker = new Caretaker();
        caretaker.addMemento("进度一", originator.createMemento());

        originator.setProgress(2);
        System.out.println("当前进度 " + originator.getProgress());

        originator.setProgress(3);
        System.out.println("当前进度 " + originator.getProgress());
        caretaker.addMemento("进度三", originator.createMemento());

        originator.restoreMemento(caretaker.getMemento("进度一"));
        System.out.println("当前进度 " + originator.getProgress());

        originator.restoreMemento(caretaker.getMemento("进度三"));
        System.out.println("当前进度 " + originator.getProgress());

    }
}

最初时,游戏进度为1,调用游戏进度生成方法,也就是发起者产生一个此刻状态下的备忘录,并且将它保存到我们的Caretaker,名字为进度一,然后们游戏进度改变,从2再到3,我们只在1和3的时候生成了备忘录,然后将它保存到了Caretaker,然后在状态3时我们恢复到了状态1,再恢复到了3

执行结果:
当前进度 1
当前进度 2
当前进度 3
当前进度 1
当前进度 3

备忘录和发起者

管理角色的功能很清晰,我们看看备忘录和发起者,发起者就是我们需要保存和恢复的,具体的备忘录也是由发起者产生的,备忘录里面需要存储的是由实际的需求来制定的,比如,有一些属性和状态无关,我们就不需要保存。备忘录模式比起其他模式算是比较简单的,不管是使用还是实现,但是它也有自己明显的优缺点:

优点:

  • 当发起人角色中的状态改变时,有可能这是个错误的改变,我们使用备忘录模式就可以把这个错误的改变还原。
  • 备份的状态是保存在发起人角色之外的,这样,发起人角色就不需要对各个备份的状态进行管理。

缺点:

  • 在实际应用中,备忘录模式都是多状态和多备份的,发起人角色的状态需要存储到备忘录对象中,对资源的消耗是比较严重的。
坚持原创分享,您的支持将鼓励我不断前行!