大話設計模式筆記(十五)の備忘錄模式

舉個栗子

問題描述

打遊戲存進度。數據庫

簡單實現

GameRole

/**
 * 遊戲角色
 * Created by callmeDevil on 2019/8/11.
 */
public class GameRole {

    // 生命力
    private int vit;
    // 攻擊力
    private int atk;
    // 防護力
    private int def;

    // 狀態顯示
    public void stateDisplay() {
        System.out.println("角色當前狀態:");
        System.out.println(String.format("體力:%s", this.vit));
        System.out.println(String.format("攻擊力:%s", this.atk));
        System.out.println(String.format("防護力:%s", this.def));
        System.out.println();
    }

    //  得到初始狀態
    public void getInitState() {
        // 數據一般來自本機磁盤或遠程數據庫
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }

    // 戰鬥
    public void fight(){
        // 在與Boss大戰後遊戲數據損耗爲0
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }

    // 省略 get set
    
}

測試

public class Test {
    public static void main(String[] args) {
        // 大戰Boss前
        GameRole lufi = new GameRole();
        // 得到初始角色狀態
        lufi.getInitState();
        lufi.stateDisplay();
        // 經過「遊戲角色」新實例,保存進度
        GameRole backup = new GameRole();
        backup.setVit(lufi.getVit());
        backup.setAtk(lufi.getAtk());
        backup.setDef(lufi.getDef());
        // 大戰Boss時,損耗嚴重,所有爲0
        lufi.fight();
        lufi.stateDisplay();
        // GameOver不甘心,恢復進度,從新玩過
        lufi.setVit(backup.getVit());
        lufi.setAtk(backup.getAtk());
        lufi.setDef(backup.getDef());
        lufi.stateDisplay();
    }
}

測試結果

角色當前狀態:
體力:100
攻擊力:100
防護力:100

角色當前狀態:
體力:0
攻擊力:0
防護力:0

角色當前狀態:
體力:100
攻擊力:100
防護力:100

存在問題

在客戶端調用這段,把整個遊戲角色的細節暴露了,職責太大,須要知道遊戲角色的生命力、攻擊力、防護力這些細節,還要進行備份。若是之後須要增長「魔法力」或修改現有的某種力,那這部分代碼就須要修改,一樣恢復時也是同樣的問題。測試

備忘錄模式

定義

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

UML圖

代碼實現

GameRole

/**
 * 遊戲角色
 * Created by callmeDevil on 2019/8/11.
 */
public class GameRole {

    // 屬性與簡單實現GameRole相同

    // 保存角色狀態
    public RoleStateMemento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }

    // 恢復角色狀態
    public void recoveryState(RoleStateMemento memento) {
        this.vit = memento.getVit();
        this.atk = memento.getAtk();
        this.def = memento.getDef();
    }

    // 其他方法與簡單實現相同
    
}

RoleStateMemento

/**
 * 角色狀態存儲類
 * Created by callmeDevil on 2019/8/11.
 */
public class RoleStateMemento {

    // 屬性與 簡單實現 GameRole 相同

    // 將生命力、攻擊力、防護力存入狀態存儲箱對象中
    public RoleStateMemento(int vit, int atk, int def){
        this.vit = vit;
        this.atk = atk;
        this.def = def;
    }

    // 省略 get set

}

RoleStateCaretaker

/**
 * 遊戲狀態管理者
 * Created by callmeDevil on 2019/8/11.
 */
public class RoleStateCaretaker {

    private RoleStateMemento memento;

    // 省略 get set

}

測試

public class Test {
    public static void main(String[] args) {
        // 大戰Boss前
        GameRole lufi = new GameRole();
        lufi.getInitState();
        lufi.stateDisplay();
        // 保存遊戲進度
        RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
        stateAdmin.setMemento(lufi.saveState());// 將具體數據封裝在了 Memento中
        // 大戰Boss時,損耗嚴重
        lufi.fight();
        lufi.stateDisplay();
        // 恢復狀態
        lufi.recoveryState(stateAdmin.getMemento());
        lufi.stateDisplay();
    }
}

測試結果

與簡單實現相同code

總結

  • 把要保存的細節給封裝在了 Memento 中,哪一天要更改保存細節也不用影響客戶端。
  • 備忘錄模式比較適用於功能比較複雜的,但須要維護或記錄屬性歷史的類,或者須要保存的屬性只是衆多屬性的一小部分時,Originator 能夠根據保存的 Memento 信息還原到前一狀態。
  • 若是在某個系統中使用命令模式時,須要實現命令的撤銷功能,那麼命令模式可使用備忘錄模式來存儲可撤銷操做的狀態。
  • 使用備忘錄能夠把複雜的對象內部信息對其餘的對象屏蔽起來。
相關文章
相關標籤/搜索