1. 程式人生 > 程式設計 >例項講解JAVA設計模式之備忘錄模式

例項講解JAVA設計模式之備忘錄模式

在講述這個模式之前,我們先看一個案例:遊戲回檔

遊戲的某個場景,一遊戲角色有生命力、攻擊力、防禦力等資料,在打Boss前和後會不一樣,我們允許玩家如果感覺與Boss決鬥的效果不理想,可以讓遊戲恢復到決鬥前。下面是程式碼:

遊戲角色類,用來儲存角色的生命力、攻擊力、防禦力的資料。

public class GameRole {
  private int vit;//生命力
  private int atk;//攻擊力
  private int def;//防禦力
  
  //狀態顯示
  public void stateDisplay() {
    System.out.println("當前角色狀態:");
    System.out.println("體力:"+this.vit);
    System.out.println("攻擊力"+this.atk);
    System.out.println("防禦力"+this.def);
  }
  //獲取初始狀態
  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;
  }
  //省略getter、setter方法
  
}
//測試方法
public class Test {
  public static void main(String[] args) {
    //大戰Boss前
    GameRole lixiaoyao = new GameRole();
    lixiaoyao.getInitState();//Boss大戰前,獲得角色初始狀態
    lixiaoyao.stateDisplay();
    
    //儲存進度,通過遊戲角色的新例項來儲存進度
    GameRole backup = new GameRole();
    backup.setVit(lixiaoyao.getVit());
    backup.setAtk(lixiaoyao.getAtk());
    backup.setDef(lixiaoyao.getDef());
    
    //大戰Boss時,損耗嚴重,所有資料全部損耗為0
    lixiaoyao.fight();
    lixiaoyao.stateDisplay();
    
    //恢復之前狀態,重新來玩
    lixiaoyao.setVit(backup.getVit());
    lixiaoyao.setAtk(backup.getAtk());
    lixiaoyao.setDef(backup.getDef());
    lixiaoyao.stateDisplay();
    
  }
}

上面的程式碼實現了效果,但是不理想的是:main方法裡暴露了太多“細節”,使得main方法需要知道“生命力、攻擊力、防禦力”這樣的細節。以後需要增加“魔法值”或修改現有的“生命力”為“經驗值”,這部分就要修改了。同樣的道理也存在於恢復時的程式碼。顯然,我們希望的是把這些“遊戲角色”的存取狀態細節封裝起來,而且最好是封裝在外部的類中。以體現職責分離。

下面介紹備忘錄模式:http://www.runoob.com/design-pattern/memento-pattern.html

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

用備忘錄模式優化案例

public class GameRole {
  private int vit;//生命力
  private int atk;//攻擊力
  private int def;//防禦力
  
  //狀態顯示
  public void stateDisplay() {
    System.out.println("當前角色狀態:");
    System.out.println("體力:"+this.vit);
    System.out.println("攻擊力"+this.atk);
    System.out.println("防禦力"+this.def);
  }
  //獲取初始狀態
  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;
  }
  //新增“儲存角色狀態”方法,將遊戲角色的三個狀態值通過例項化“角色狀態儲存箱”返回
  public RoleStateMemento saveState() {
    return new RoleStateMemento(vit,atk,def);
  }
  
  //新增“恢復角色狀態”方法,可將外部的“角色狀態儲存箱”中的狀態值恢復給遊戲角色
  public void recoveryState(RoleStateMemento memento) {
    this.vit = memento.getAtk();
    this.atk = memento.getAtk();
    this.def = memento.getDef();
  }
  
  //省略getter、setter方法
  
}
//角色狀態儲存箱類
public class RoleStateMemento {
  private int vit;//生命力
  private int atk;//攻擊力
  private int def;//防禦力
  //將生命力、攻擊力、防禦力存入狀態儲存箱物件中
  public RoleStateMemento(int vit,int atk,int def) {
    super();
    this.vit = vit;
    this.atk = atk;
    this.def = def;
  }
  
  //省略getter、setter方法
  
}
//角色狀態管理者類
public class RoleStateCaretaker {
  private RoleStateMemento memento;

  public RoleStateMemento getMemento() {
    return memento;
  }

  public void setMemento(RoleStateMemento memento) {
    this.memento = memento;
  }
  
}
//測試方法
public class Test {
  public static void main(String[] args) {
    //大戰Boss前
    GameRole lixiaoyao = new GameRole();
    lixiaoyao.getInitState();//Boss大戰前,獲得角色初始狀態
    lixiaoyao.stateDisplay();
    
    //儲存進度,由於封裝在Memento中,因此我們並不知道儲存了哪些具體的資料
    RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
    stateAdmin.setMemento(lixiaoyao.saveState());
    
    //大戰Boss時,損耗嚴重
    lixiaoyao.fight();
    lixiaoyao.stateDisplay();
    
    //恢復之前的狀態
    lixiaoyao.recoveryState(stateAdmin.getMemento());
    lixiaoyao.stateDisplay();
    
  }
}

輸出結果同上。

肯定有人會問:對於“角色狀態”的儲存,直接呼叫RoleStateMemento進行set和get不就行了,為什麼還需要一個RoleStateCaretaker類呢?

這是為了符合迪米特法則進行的優化!

備忘錄模式也是有缺點的,角色狀態需要完整儲存到備忘錄物件中,如果狀態資料很大很多,那麼在資源消耗上,備忘錄物件會非常耗記憶體。所以也不是用的越多越好。

以上就是例項講解JAVA設計模式之備忘錄模式的詳細內容,更多關於JAVA 備忘錄模式的資料請關注我們其它相關文章!