设计模式(十八)备忘录
一、定義
在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),這樣就可以在以后將對(duì)象恢復(fù)到原先保存的狀態(tài)。備忘錄模式是一種對(duì)象行為型模式,其別名為標(biāo)記(Token)模式。
二、描述
備忘錄模式的核心在于備忘錄類以及用于管理備忘錄的負(fù)責(zé)人類的設(shè)計(jì),包含以下三個(gè)角色:
1、Originator(原發(fā)器):原發(fā)器是一個(gè)普通類,它通過創(chuàng)建一個(gè)備忘錄來(lái)存儲(chǔ)其當(dāng)前內(nèi)部狀態(tài),也可以使用備忘錄來(lái)恢復(fù)其內(nèi)部狀態(tài),一般將需要保存內(nèi)部狀態(tài)的類設(shè)計(jì)為原發(fā)器。
2、Memento(備忘錄):備忘錄用于存儲(chǔ)原發(fā)器的內(nèi)部狀態(tài),根據(jù)原發(fā)器來(lái)決定保存哪些內(nèi)部狀態(tài)。備忘錄的設(shè)計(jì)一般可以參考原發(fā)器的設(shè)計(jì),根據(jù)實(shí)際需要確定備忘錄類中的屬性。用戶需要注意的是,除了原發(fā)器本身與負(fù)責(zé)人類之外,備忘錄對(duì)象不能直接供其他類使用,原發(fā)器的設(shè)計(jì)在不同的編程語(yǔ)言中實(shí)現(xiàn)機(jī)制會(huì)有所不同。
3、Caretaker(負(fù)責(zé)人):負(fù)責(zé)人又稱為管理者,它負(fù)責(zé)保存?zhèn)渫洠遣荒軐?duì)備忘錄的內(nèi)容進(jìn)行操作或檢查。在負(fù)責(zé)人類中可以存儲(chǔ)一個(gè)或多個(gè)備忘錄對(duì)象,它只負(fù)責(zé)存儲(chǔ)對(duì)象,不能修改對(duì)象,也無(wú)須知道對(duì)象的實(shí)現(xiàn)細(xì)節(jié)。
三、例子
X公司欲開發(fā)一款中國(guó)象棋App,基于新手友好、及防誤觸等原因,設(shè)計(jì)App具有“悔棋”功能,可恢復(fù)到前一步
Chessman:原發(fā)器
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;
}
// 保存狀態(tài)
public ChessmanMemento Save()
{
return new ChessmanMemento(Label, X, Y);
}
// 恢復(fù)狀態(tài)
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:負(fù)責(zé)人
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:測(cè)試代碼
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)
{
// 保存?zhèn)渫? mementoCaretaker.SetMemento(chess.Save());
index++;
Console.WriteLine("棋子 {0} 當(dāng)前位置為 第 {1} 行 第 {2} 列", chess.Label, chess.X, chess.Y);
}
// 悔棋
void Undo(Chessman chess, int i)
{
Console.WriteLine("---------- Sorry,俺悔棋了 ---------");
index--;
// 撤銷到上一個(gè)備忘錄
chess.Restore(mementoCaretaker.GetMemento(i - 1));
Console.WriteLine("棋子 {0} 當(dāng)前位置為 第 {1} 行 第 {2} 列", chess.Label, chess.X, chess.Y);
}
// 撤銷悔棋
void Redo(Chessman chess, int i)
{
Console.WriteLine("---------- Sorry,撤銷悔棋 ---------");
index++;
// 恢復(fù)到下一個(gè)備忘錄
chess.Restore(mementoCaretaker.GetMemento(i + 1));
Console.WriteLine("棋子 {0} 當(dāng)前位置為 第 {1} 行 第 {2} 列", chess.Label, chess.X, chess.Y);
}
Console.ReadLine();
四、總結(jié)
1、優(yōu)點(diǎn)
(1)備忘錄模式提供了一種狀態(tài)恢復(fù)的實(shí)現(xiàn)機(jī)制,使得用戶可以方便地回到一個(gè)特定的歷史步驟,當(dāng)新的狀態(tài)無(wú)效或者存在問題時(shí),可以使用暫時(shí)存儲(chǔ)起來(lái)的備忘錄將狀態(tài)復(fù)原。
(2)備忘錄模式實(shí)現(xiàn)了對(duì)信息的封裝,一個(gè)備忘錄對(duì)象是一種原發(fā)器對(duì)象狀態(tài)的表示,不會(huì)被其他代碼所改動(dòng)。備忘錄保存了原發(fā)器的狀態(tài),采用列表、堆棧等集合來(lái)存儲(chǔ)備忘錄對(duì)象,可以實(shí)現(xiàn)多次撤銷操作。
2、缺點(diǎn)
(1)備忘錄模式資源消耗過大,如果需要保存的原發(fā)器類的成員變量太多,就不可避免地需要占用大量的存儲(chǔ)空間,每保存一次對(duì)象狀態(tài)都需要消耗一定系統(tǒng)資源。
總結(jié)
以上是生活随笔為你收集整理的设计模式(十八)备忘录的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文献论文保存地
- 下一篇: 聊聊流式数据湖Paimon(一)