在大部分遊戲中,都有一個“存檔點”的概念。例如,在挑戰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,所在位置:世界之石
以上就是備忘錄模式的說明,希望能對大家有所幫助。