設計模式之備忘錄模式
備忘錄模式:
在不破壞封裝性的前提下,鋪貨一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可將該對象恢複到原先保存的狀態。
備忘錄模式結構圖:

Originator(原生者): 需要被保存狀態以便恢複的那個對象。
Memento(備忘錄) : 該對象由Originator創建,主要用來保存Originator的內部狀態。
Caretaker(管理者):負責在適當的時間保存/恢複Originator對象的狀態。
適用性:
1)必須保存一個對象在某一個時刻的(部分)狀態,這樣以後需要時它才能恢複到先前的狀態。
2)如果一個用接口來讓其它對象直接得到這些狀態,將會暴露對象的實現細節並破壞對象的封裝性。
優缺點:
1) 保持封裝邊界 使用備忘錄可以避免暴露一些隻應由原發器管理卻又必須存儲在原發器之外的信息。該模式把可能很複雜的Originator內部信息對其他對象屏蔽起來,從而保持了封裝邊界。
2) 它簡化了原發器 在其他的保持封裝性的設計中,Originator負責保持客戶請求過的內部狀態版本。這就把所有存儲管理的重任交給了Originator。讓客戶管理它們請求的狀態將會簡化Originator,並且使得客戶工作結束時無需通知原發器。
3) 使用備忘錄可能代價很高 如果原發器在生成備忘錄時必須拷貝並存儲大量的信息,或者客戶非常頻繁地創建備忘錄和恢複原發器狀態,可能會導致非常大的開銷。除非封裝和恢複Originator狀態的開銷不大,否則該模式可能並不合適。
4) 維護備忘錄的潛在代價 管理器負責刪除它所維護的備忘錄。然而,管理器不知道備忘錄中有多少個狀態。因此當存儲備忘錄時,一個本來很小的管理器,可能會產生大量的存儲開銷。
例子:
static void Main(string[] args)
{
//大戰Boss前
GameRole lixiaoyao = new GameRole();
lixiaoyao.GetIniState();
lixiaoyao.StateDisplay();
//保存進度
RoleStateCaretaker stateAdmin = new RoleStateCaretaker();
stateAdmin.Memento = lixiaoyao.SaveState();
//大戰Boss時,損耗嚴重
lixiaoyao.Fight();
lixiaoyao.StateDisplay();
//恢複之前狀態
lixiaoyao.RecoveryState(stateAdmin.Memento);
lixiaoyao.StateDisplay();
Console.Read();
}
class GameRole
{
//生命力
private int vit;
public int Vitality
{
get { return vit; }
set { vit = value; }
}
//攻擊力
private int atk;
public int Attack
{
get { return atk; }
set { atk = value; }
}
//防禦力
private int def;
public int Defense
{
get { return def; }
set { def = value; }
}
//狀態顯示
public void StateDisplay()
{
Console.WriteLine("角色當前狀態:");
Console.WriteLine("體力:{0}", this.vit);
Console.WriteLine("攻擊力:{0}", this.atk);
Console.WriteLine("防禦力:{0}", this.def);
Console.WriteLine("");
}
//獲得初始狀態
public void GetIniState()
{
this.vit = 100;
this.atk = 100;
this.def = 100;
}
//戰鬥
public void Fight()
{
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.Vitality;
this.atk = memento.Attack;
this.def = memento.Defense;
}
}
//角色狀態存儲類
class RoleStateMemento
{
private int vit;
private int atk;
private int def;
public RoleStateMemento (int vit,int atk,int def)
{
this.vit = vit;
this.atk = atk;
this.def = def;
}
//生命力
public int Vitality
{
get { return vit; }
set { vit = value; }
}
//攻擊力
public int Attack
{
get { return atk; }
set { atk = value; }
}
//防禦力
public int Defense
{
get { return def; }
set { def = value; }
}
}
//角色狀態管理類
class RoleStateCaretaker
{
private RoleStateMemento memento;
public RoleStateMemento Memento
{
get { return memento; }
set { memento = value; }
}
}
備忘錄模式與事務回滾
這個例子應該說對於男生比較熟悉,在打CF時,如果沒血了,我們會重新開始遊戲,又恢複了有血的狀態,也可以通過加血,來恢複到原來的攻擊力、防禦力,備忘錄模式的學習讓我想起了之前學習過的回滾事件,這兩者有一個共同點就是可以通過存儲恢複到之前的某一時刻。而備忘錄模式 是隻要你在代碼中使用了此模式,在你需要備份時,就可以備份,不存在處理過程是否出錯。
而事務回滾是這樣定義的,一組業務整體處理的行為叫一個事務。這一組的業務都能成功處理,我們就可以把這個事務提交來保存你已做的行為結果。但如果一組中有任何的差錯出現的話,我們就認為這事務不成功,需要回滾來撤消之前的操作。意思是說隻有在事務出現差錯時才會使用事務回滾,而如果正常情況下,事務會正常運行下去,不會返回到某一時刻的。
最後更新:2017-04-03 12:55:07