Java設計模式之從[暗黑破壞神存檔點]分析備忘錄(Memento)模式
阿新 • • 發佈:2018-12-26
在大部分遊戲中,都有一個“存檔點”的概念。例如,在挑戰boss前,遊戲會在某個地方存檔,如果玩家挑戰boss失敗,則會從這個存檔點開始重新遊戲。因此,我們可以將這個“存檔點”當成是一個備忘錄,我們將此時玩家所有的狀態儲存下來,以便之後的讀取。
備忘錄模式正是如此,它在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可以將該物件恢復到原先的儲存狀態了。
一個簡單的例子,假設玩家在暗黑破壞神中準備挑戰Boss巴爾,玩家攜帶了10瓶藥劑,並且在巴爾的門前“世界之石”存了檔,玩家在挑戰Boss時使用了1瓶藥劑,後來挑戰失敗了,於是他重新讀檔,再次回到了世界之石,此時他身上攜帶的藥劑數量仍然應該為10瓶。
具體的程式碼如下:
interface IMemento{ } class CharacterOriginator{ private int potion; private String position; public void move(String place){ position = place; } public void usePotion(){ potion --; } public int getPotion() { return potion; } private void setPotion(int potion) { this.potion = potion; } public String getPosition() { return position; } private void setPosition(String position) { this.position = position; } public IMemento createMemento(){ return new Memento(potion, position); } public void restoreMemento(IMemento memento){ setPotion(((Memento)memento).getPotion()); setPosition(((Memento)memento).getPosition()); } public CharacterOriginator(int potion, String position){ this.potion = potion; this.position = position; } private class Memento implements IMemento{ private int potion; String position; public Memento(int potion, String position){ this.potion = potion; this.position = position; } public int getPotion() { return potion; } public String getPosition() { return position; } } } class Caretaker{ IMemento memento; public IMemento getMemento() { return memento; } public void setMemento(IMemento memento) { this.memento = memento; } } class Memento { public static void main(String[] args) { CharacterOriginator player = new CharacterOriginator(10, "世界之石"); Caretaker caretaker = new Caretaker(); caretaker.setMemento(player.createMemento()); System.out.printf("玩家攜帶的藥劑:%d,所在位置:%s\n", player.getPotion(), player.getPosition()); player.usePotion(); player.move("巴爾的宮殿"); //玩家挑戰失敗後重新讀檔 System.out.printf("玩家攜帶的藥劑:%d,所在位置:%s\n", player.getPotion(), player.getPosition()); player.restoreMemento(caretaker.getMemento()); System.out.printf("玩家攜帶的藥劑:%d,所在位置:%s\n", player.getPotion(), player.getPosition()); }
現在來分析一下上面的程式碼,並同時講解備忘錄模式。備忘錄模式有3個參與者:Originator——負責建立備忘錄、還原備忘錄,人物的各種狀態都在此,如例子中的CharacterOriginator。Memento——備忘錄,它表示需要儲存哪些資料,Originator通過需要在備忘錄上取資料。在上例中,Memento為Originator的一個內部類。Caretaker——負責儲存、獲取Memento。為了不暴露Memento的內部方法(我們認為,Memento的內部方法只能由CharacterOriginator獲取),我們讓Memento繼承了一個空介面IMemento,因此通過Caretaker獲得的備忘錄均是IMemento型別的,我們無法對它做任何事情,但是可以把它傳給CharacterOriginator,然後Originator的restoreMemento可以把IMemento型別強制轉換為Memento型別。請注意,由於Memento為內部私有類,因此除了CharacterOriginator外,其餘的類無法呼叫Memento的方法,這也就是我們說的“不暴露Memento內部方法”。restoreMemento中清晰寫明瞭應該還原哪些狀態,在這裡就不進行詳細解釋了。
最後我們看看main方法。首先例項化了一個玩家(player),他有10瓶藥水,位於世界之石;隨後他進入了巴爾的宮殿,並用掉了一瓶藥水;最後,他由於挑戰失敗而恢復到了以前的存檔點——擁有10瓶藥水,位於世界之石。因此,程式執行的結果為:
玩家攜帶的藥劑:10,所在位置:世界之石
玩家攜帶的藥劑:9,所在位置:巴爾的宮殿
玩家攜帶的藥劑:10,所在位置:世界之石
以上就是備忘錄模式的說明,希望能對大家有所幫助。