Android開發設計模式之備忘錄模式解析

Android開發設計模式之備忘錄模式解析。

一、介紹

備忘錄模式是一種行為模式,該模式用於保存對象當前狀態,並且在之後可以再次恢復到此狀態,這有點像我們平時說的”後悔藥“。備忘錄模式實現的方式需要保證被保存的對象狀態不能被對象從外部訪問,目的是為瞭保護好被保存的這些對象狀態的完整性以及內部實現不向外暴露。

二、定義

在不破壞封閉的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣,以後就可將該對象恢復到原先保存的狀態。

三、使用場景

需要保存一個對象在某一個時刻的狀態或部分狀態。

如果用一個接口來讓其他對象得到這些狀態,將會暴露對象的實現細節並破壞對象的封裝性,一個對象不希望外界直接訪問其內部狀態,通過中間對象可以間接訪問其內部狀態。

四、備忘錄模式的UML類圖

UML類圖:

這裡寫圖片描述

角色介紹:

Originator:負責創建一個備忘錄,可以記錄、恢復自身的內部狀態。同時Originator還可以根據需要決定Memento存儲自身的哪些內部狀態。

Memento:備忘錄角色,用於存儲Originator的內部狀態,並且可以防止Originator以外的對象訪問Memento。

Caretaker:負責存儲備忘錄,不能對備忘錄的內容進行操作和訪問,隻能將備忘錄傳遞給其他對象。

五、簡單示例

對備忘錄模式來說,比較貼切的場景應該是遊戲中的存檔功能,該功能就是將遊戲進度存儲到本地文件系統或數據庫中,下次再次進入時從本地加載進度,使得玩傢能夠繼續上一次的遊戲之旅,這裡我們就以”使命召喚“這款遊戲為例來簡單演示一下備忘錄模式的實現。

首先我們建立遊戲類、備忘錄類、Caretaker類,玩遊戲到某個節點對遊戲進行存檔,然後退出遊戲,再重新進入時從存檔中讀取進行,並且進入存檔時的進度。

遊戲類:

/**
 * 
 * 簡單模擬“使命召喚”遊戲 
 * 
 */

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 + "]";
    }
}

在CallOfDuty遊戲類中,我們存儲瞭幾個關鍵字段,關卡、人物的生命值、武器,當調用play函數玩遊戲時,我們對關卡和人物的生命值進行修改。在該類中可以通過createMemoto函數來創建該用戶的備忘錄對象,也就是將自身的狀態保存到一個Memoto對象中。外部可以通過restore函數將CallOfDuty對象的狀態從備忘錄對象中恢復。

我們在來看下備忘錄對象,它隻是存儲CallOfDuty對象的字段,具體代碼如下:

備忘錄類:

/**
 * 備忘錄類
 */
public class Memento {
    public int mCheckpoint;//武器

    public int mLiftValue;//生命

    public String mWeapon;//關卡

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

}

這是一個無狀態、無操作的實體類,隻負責用來存儲Originator角色的一些數據,防止外部直接訪問Originator。

而備忘錄的操作者則是Caretaker角色,我們看下相關代碼:

Caretaker類:

/**
 * Caretaker,負責管理Memento
 */
public class Caretaker {

    Memento mMemento; //備忘錄

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

    /**
     * 獲取存檔
     */
    public Memento getMemento(){
        return mMemento;
    }
}

Caretaker類的職責很簡單,就是負責管理Memoto對象,也就是備忘錄對象。

客戶端類:

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());
    }
}

結果:

打遊戲:第1關奮戰殺敵中
進度升級瞭
到達第2關
--------------
退出前的遊戲屬性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鷹]
退出遊戲
--------------
恢復後的遊戲屬性:CallOfDuty [mCheckpoint=2,mLiftValue=90,mWeapon=沙漠之鷹]
打遊戲:第2關奮戰殺敵中

上述過程大致有如下4步:
(1)開始遊戲,闖關升級;
(2)遊戲退出之前進行存檔;
(3)退出遊戲;
(4)重新啟動遊戲,從存檔中恢復遊戲進度。

CallOfDuty在這裡為Originator角色,也就是需要存儲數據的對象,在這裡並沒有直接存儲CallOfDuty的對象,而是通過Memoto對CallOfDuty對象的數據進行存儲,然後在存儲Memoto對象,最終對Memoto的存取操作則交給Caretaker對象。在這個過程中,各個角色職責清晰、單一,代碼也比較簡單,即對外屏蔽瞭對CallOfDuty角色的直接訪問,在滿足瞭對象狀態存取功能的同時也使得該模塊的結構保持清晰、整潔。

六、Android源碼中的備忘錄模式

1、onSaveInstanceState和onRestoreInstanceState

當Activity不是正常方式退出,且Activity在隨後的時間內被系統殺死之前會調用這兩個方法讓開發人員可以有機會存儲Activity相關信息,且在下次返回Activity時恢復這些數據。通過這兩個函數。開發人員能夠在某些特殊場景下儲存與界面相關的信息,提升用戶體驗。

七、總結

備忘錄模式是在不破壞封裝的條件下,通過備忘錄對象(Memoto)存儲另外一個對象內部狀態的快照,在將來合適的時候把這個對象還原到存儲起來的狀態。

優點:

給用戶提供瞭一種可以恢復狀態的機制,可以使用戶能夠比較方便地回到某個歷史狀態。

實現瞭信息的封裝,使用戶不需要關心狀態的保存細節。

缺點:

消耗資源,如果類的成員變量過多,勢必會占用比較大的資源,而且每一次保存都會消耗一定的內存。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *