例項講解JAVA設計模式之備忘錄模式
阿新 • • 發佈:2020-06-26
在講述這個模式之前,我們先看一個案例:遊戲回檔
遊戲的某個場景,一遊戲角色有生命力、攻擊力、防禦力等資料,在打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 備忘錄模式的資料請關注我們其它相關文章!