一、定義 在不破壞封裝的前提下,捕獲一個對象的內部狀態,併在該對象之外保存這個狀態,這樣就可以在以後將對象恢復到原先保存的狀態。備忘錄模式是一種對象行為型模式,其別名為標記(Token)模式。 二、描述 備忘錄模式的核心在於備忘錄類以及用於管理備忘錄的負責人類的設計,包含以下三個角色: 1、Orig ...
一、定義
在不破壞封裝的前提下,捕獲一個對象的內部狀態,併在該對象之外保存這個狀態,這樣就可以在以後將對象恢復到原先保存的狀態。備忘錄模式是一種對象行為型模式,其別名為標記(Token)模式。
二、描述
備忘錄模式的核心在於備忘錄類以及用於管理備忘錄的負責人類的設計,包含以下三個角色:
1、Originator(原發器):原發器是一個普通類,它通過創建一個備忘錄來存儲其當前內部狀態,也可以使用備忘錄來恢復其內部狀態,一般將需要保存內部狀態的類設計為原發器。
2、Memento(備忘錄):備忘錄用於存儲原發器的內部狀態,根據原發器來決定保存哪些內部狀態。備忘錄的設計一般可以參考原發器的設計,根據實際需要確定備忘錄類中的屬性。用戶需要註意的是,除了原發器本身與負責人類之外,備忘錄對象不能直接供其他類使用,原發器的設計在不同的編程語言中實現機制會有所不同。
3、Caretaker(負責人):負責人又稱為管理者,它負責保存備忘錄,但是不能對備忘錄的內容進行操作或檢查。在負責人類中可以存儲一個或多個備忘錄對象,它只負責存儲對象,不能修改對象,也無須知道對象的實現細節。
三、例子
X公司欲開發一款中國象棋App,基於新手友好、及防誤觸等原因,設計App具有“悔棋”功能,可恢復到前一步
Chessman:原發器
public class Chessman
{
public string Label { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Chessman(string label, int x, int y)
{
Label = label;
X = x;
Y = y;
}
// 保存狀態
public ChessmanMemento Save()
{
return new ChessmanMemento(Label, X, Y);
}
// 恢復狀態
public void Restore(ChessmanMemento memento)
{
Label = memento.Label;
X = memento.X;
Y = memento.Y;
}
}
ChessmanMemento:備忘錄
public class ChessmanMemento
{
public string Label { get; set; }
public int X { get; set; }
public int Y { get; set; }
public ChessmanMemento(string label, int x, int y)
{
Label = label;
X = x;
Y = y;
}
}
MementoCaretaker:負責人
public class MementoCaretaker
{
private IList<ChessmanMemento> mementoList = new List<ChessmanMemento>();
public ChessmanMemento GetMemento(int i)
{
return mementoList[i];
}
public void SetMemento(ChessmanMemento memento)
{
mementoList.Add(memento);
}
}
Program:測試代碼
private static int index = -1;
private static MementoCaretaker mementoCaretaker = new MementoCaretaker();
Chessman chess = new Chessman("車", 1, 1);
Play(chess);
chess.Y = 4;
Play(chess);
chess.X = 5;
Play(chess);
Undo(chess, index);
Undo(chess, index);
Redo(chess, index);
Redo(chess, index);
// 下棋
void Play(Chessman chess)
{
// 保存備忘錄
mementoCaretaker.SetMemento(chess.Save());
index++;
Console.WriteLine("棋子 {0} 當前位置為 第 {1} 行 第 {2} 列", chess.Label, chess.X, chess.Y);
}
// 悔棋
void Undo(Chessman chess, int i)
{
Console.WriteLine("---------- Sorry,俺悔棋了 ---------");
index--;
// 撤銷到上一個備忘錄
chess.Restore(mementoCaretaker.GetMemento(i - 1));
Console.WriteLine("棋子 {0} 當前位置為 第 {1} 行 第 {2} 列", chess.Label, chess.X, chess.Y);
}
// 撤銷悔棋
void Redo(Chessman chess, int i)
{
Console.WriteLine("---------- Sorry,撤銷悔棋 ---------");
index++;
// 恢復到下一個備忘錄
chess.Restore(mementoCaretaker.GetMemento(i + 1));
Console.WriteLine("棋子 {0} 當前位置為 第 {1} 行 第 {2} 列", chess.Label, chess.X, chess.Y);
}
Console.ReadLine();
四、總結
1、優點
(1)備忘錄模式提供了一種狀態恢復的實現機制,使得用戶可以方便地回到一個特定的歷史步驟,當新的狀態無效或者存在問題時,可以使用暫時存儲起來的備忘錄將狀態複原。
(2)備忘錄模式實現了對信息的封裝,一個備忘錄對象是一種原發器對象狀態的表示,不會被其他代碼所改動。備忘錄保存了原發器的狀態,採用列表、堆棧等集合來存儲備忘錄對象,可以實現多次撤銷操作。
2、缺點
(1)備忘錄模式資源消耗過大,如果需要保存的原發器類的成員變數太多,就不可避免地需要占用大量的存儲空間,每保存一次對象狀態都需要消耗一定系統資源。
測試簽名