第十三章、备忘录模式

备忘录模式是一种行为模式,该模式用于保存对象当前的状态,并且在之后可以再次恢复到此状态,有点像是我们平常说的”后悔药”。

1.定义

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

2.使用场景

(1)需要保存一个对象在某一个时刻的状态或部分状态。

(2)如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其内部状态。

3.简单实现

书中例子:以”使命召唤”游戏为例,用游戏中的存档功能来举例。

首先是备忘录类

/**
 * 备忘录类
 */
public class Memento {
    public int mCheckpoint;//武器

    public int mLiftValue;//生命

    public String mWeapon;//关卡

    @Override
    public String toString() {
        return "Memento [mCheckpoint=" + mCheckpoint + ",mLiftValue="
                + mLiftValue + ",mWeapon=" + mWeapon + "]";
    }

}

游戏类,在该类可以通过createMemento函数来创建该用户的备忘录对象,外部可以通过restore函数将CallOfDuty 对象的状态从备忘录对象中恢复。

/**
 * 
 * 简单模拟“使命召唤”游戏 
 * 
 */

public class CallOfDuty {

    private int mCheckpoint = 1;

    private int mLiftValue = 100;

    private String mWeapon = "沙漠之鹰";

    //玩游戏
    public void play(){
        System.out.println("打游戏:"+String.format("第%d关", mCheckpoint) + "奋战杀敌中");
        mLiftValue -= 10;
        System.out.println("进度升级了");
        mCheckpoint++;
        System.out.println("到达" + String.format("第%d关", mCheckpoint));
    }

    //退出游戏
    public void quit(){
        System.out.println("--------------");
        System.out.println("退出前的游戏属性:" + this.toString());
        System.out.println("退出游戏");
        System.out.println("--------------");
    }

    /**
     *创建备忘录 
     */
    public Memento createMemento(){
        Memento memento = new Memento();
        memento.mCheckpoint = mCheckpoint;
        memento.mLiftValue = mLiftValue;
        memento.mWeapon = mWeapon;
        return memento;
    }

    //恢复游戏
    public void restore(Memento memento){
        this.mCheckpoint = memento.mCheckpoint;
        this.mLiftValue = memento.mLiftValue;
        this.mWeapon = memento.mWeapon;
        System.out.println("恢复后的游戏属性:" + this.toString());
    }

    //省略getter和setter方法

    @Override
    public String toString() {
        return "CallOfDuty [mCheckpoint=" + mCheckpoint + ",mLiftValue="
                + mLiftValue + ",mWeapon=" + mWeapon + "]";
    }
}

备忘录操作类:

/**
 * Caretaker,负责管理Memento
 */
public class Caretaker {

    Memento mMemento; //备忘录

    /**
     * 存档
     */
    public void archive(Memento memento){
        this.mMemento = memento;
    }

    /**
     * 获取存档
     */
    public Memento getMemento(){
        return mMemento;
    }
}

客户端使用代码:

public class Client {
    public static void main(String[] args) {
        //构建游戏对象
        CallOfDuty game = new CallOfDuty();
        //1.打游戏
        game.play();

        Caretaker caretaker = new Caretaker();
        //2.游戏存档
        caretaker.archive(game.createMemento());
        //3.退出游戏
        game.quit();
        //4.恢复游戏
        CallOfDuty newGame = new CallOfDuty();
        newGame.restore(caretaker.getMemento());

        //5.再次打游戏(不存档)
        game.play();
        //6.恢复之前存档
        newGame.restore(caretaker.getMemento());
    }
}

结果:

打游戏:第1关奋战杀敌中
进度升级了
到达第2关
--------------
退出前的游戏属性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鹰]
退出游戏
--------------
恢复后的游戏属性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鹰]
打游戏:第2关奋战杀敌中
进度升级了
到达第3关
恢复后的游戏属性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鹰]

上面的代码中,各个角色职责清晰、单一,代码也比较简单,即对外屏蔽了对CallOfDuty角色的直接访问,在满足了对象状态存取功能的同时也使得该模块的结构保持清晰、整洁。

4.Android源码中的备忘录模式

1.onSaveInstanceState和onRestoreInstanceState

当Activity不是正常方式退出,且Activity在随后的时间内被系统杀死之前会调用这两个方法让开发人员可以有机会存储Activity相关信息,且在下次返回Activity时恢复这些数据。通过这两个函数。开发人员能够在某些特殊场景下储存与界面相关的信息,提升用户体验。

5.总结

1.优点

(1)给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史状态。

(2)实现了信息的封装,使用户不需要关心状态的保存细节。

2.缺点

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