設計模式----備忘錄模式
前面說的設計模式幾乎都有用到繼承、接口,今天,我要說的這個設計模式,它就沒有用到任何接口,也不需要抽象類,更沒有復雜的繼承關系,它就是備忘錄模式,何為備忘錄,按照現實世界的理解,備忘錄就是人們在此刻記錄一些東西用作未來供我們回憶想起此刻所記錄的信息,大白話就是記錄作用,我們今天的備忘錄也是一樣的道理。
備忘錄,首先當然是備忘錄類了,請看代碼
class Memento { private string state; public Memento(string state) { this.state = state; } public string State { get { return state; } } }
這裏就是一個構造函數註入和一個屬性,因為我們是簡化版,所以只用一個屬性來替代,所謂備忘錄類,就是用來保存,這裏的state字段就是我們要保存的值,所以為什麽State這個屬性才只有get方法而沒有set方法了。備忘錄有了,肯定要有管理備忘錄的對象啊。請看下面的代碼
class Originator { privatestring state; public string State { get { return state; } set { state = value; } } public Memento CreateMemento() { return (new Memento(state)); } public void SetMemento(Memento memento) { state= memento.State; } public void Show() { Console.WriteLine("State=" + state); } }
這個對象最重要的方法就是CreateMemento方法和SetMemento方法,他們分別是創建備忘錄對象保存當前狀態和根據備忘錄狀態來恢復當前狀態,看代碼已經是很明顯了。。。,看到這裏你是否覺得哪裏還少點東西呢??備忘錄對象如何保存呢??沒有備忘錄對象又怎麽恢復呢。。所以,接下來,我們就要創建一個保存備忘錄的對象,請看代碼。。
class Caretaker { private Memento memento; public Memento Memento { get { return memento; } set { memento = value; } } }
這個對象很簡單,就是一個屬性,這個就是用來保存備忘錄對象的對象,是不是很簡單,這就是所有的備忘錄模式。好了,照老規矩,我們還是跑一遍演示一下是如何保存恢復備忘錄模式的
class Program { static void Main(string[] args) { Originator o = new Originator(); o.State = "ON"; o.Show(); Caretaker c = new Caretaker(); c.Memento = o.CreateMemento(); o.State = "Off"; o.Show(); o.SetMemento(c.Memento); o.Show(); Console.ReadLine(); } }
首先我們創建了一個Originator對象,我們設置它的初始狀態是ON,然後顯示,接下來我們創建Caretaker對象來保存初始狀態為ON的Memento對象,然後我們改變初始狀態為Off,顯示現在改變的狀態,最後我們通過我們保存的備忘錄對象來恢復到之前的狀態然後顯示出來。這就是完整的備忘錄模式,我們可以看看運行結果
第一次顯示狀態是On,接下來是Off,最後還原成On。。。
上面的那些是設計模式的框架,下面,讓我們用這個框架來實現我們今天的場景:遊戲存檔。
首先,我們根據上面的框架來設計我們的類型,首先是存檔類(備忘錄類),遊戲存檔,當然是存遊戲角色的狀態,請看代碼
/// <summary> /// 角色狀態存儲箱 /// </summary> 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; } /// <summary> /// 生命力 /// </summary> public int Vitality { get { return vit; } } /// <summary> /// 攻擊力 /// </summary> public int Atthack { get { return atk; } } /// <summary> /// 防禦力 /// </summary> public int Defense { get { return def; } } }
是不是有種似曾相識的感覺呢,如果沒有的話請看上面的Memento類,這裏我們的存檔類(備忘錄)有三個字段,分別是生命力、攻擊力和防禦力,好了,下一步就是人物類(Originator)了
class GameRole { private int vit; /// <summary> /// 生命力 /// </summary> public int Vit { get { return vit; } set { vit = value; } } private int atk; /// <summary> /// 攻擊力 /// </summary> public int Attack { get { return atk; } set { atk = value; } } private int def; /// <summary> /// 防禦力 /// </summary> public int Defense { get { return def; } set { def = value; } } /// <summary> /// 狀態顯示 /// </summary> public void StateDisplay() { Console.WriteLine("角色當前狀態:"); Console.WriteLine("體力:{0}", vit); Console.WriteLine("攻擊力:{0}", atk); Console.WriteLine("防禦力:{0}", def); Console.WriteLine(""); } /// <summary> /// 獲得初始狀態 /// </summary> public void GetInitState() { this.vit = 100; this.atk = 100; this.def = 100; } /// <summary> /// 戰鬥 /// </summary> public void Fight() { this.vit = 50; this.def = 50; this.atk = 50; } /// <summary> /// 保存角色狀態 /// </summary> /// <returns></returns> public RoleStateMemento SaveState() { return (new RoleStateMemento(vit, atk, def)); } //恢復角色狀態 public void RecoveryState(RoleStateMemento memento) { this.vit = memento.Vitality; this.atk = memento.Atthack; this.def = memento.Defense; } }
同樣的道理,它我們之前也認識過了,只是多了一點東西而已,但是這些並不會影響整個備忘錄的框架,所以,我們從這裏由此可以得出Originator類就是我們的實際業務類型,當然,我們大多數項目中一個對象(Model)幾乎都是用來充當一個傳值對象,不會像這樣有業務邏輯在裏面,在軟件中這種現象它們都有專業的名詞解釋,我們稱之為貧血模式(無業務邏輯)和充血模式(有業務邏輯),定義我最後再來說,我們先把備忘錄模式,不,是遊戲存檔說完哈,好了備忘錄的其中兩個對象已經出來了,接下來第三位對象也要出來亮個相了,相信我們已經都猜到它了,沒錯,它就是用來保存遊戲對象(備忘錄對象)的對象
/// <summary> /// 角色狀態管理者 /// </summary> class RoleStateCaretaker { private RoleStateMemento memento; public RoleStateMemento Memento { get { return memento; } set { memento = value; } } }
所以,上面這個對象就是個類型為RoleStateMemento對象的類型。到這裏,我們的遊戲存檔就完成了,雖然不是真實的業務場景,但是已經比備忘錄模式的框架要好理解的多了,接下來我們就來實現我們的遊戲存檔了
class Program { static void Main(string[] args) { //大戰Boss前 GameRole lixiaoyao = new GameRole(); lixiaoyao.GetInitState(); lixiaoyao.StateDisplay(); //保存進度 RoleStateCaretaker stateAdmin = new RoleStateCaretaker(); stateAdmin.Memento = lixiaoyao.SaveState(); //大戰Boss時,損耗嚴重 lixiaoyao.Fight(); lixiaoyao.StateDisplay(); //恢復之前狀態 lixiaoyao.RecoveryState(stateAdmin.Memento); lixiaoyao.StateDisplay(); Console.Read(); } }
首先我們創建了一個李逍遙的角色(咳咳),這個名字隨意,然後顯示角色初始值,然後我們先保存我們創建的這個李逍遙對象,這樣我們就可以義無反顧的去殺Boss了,由於Boss過於強大,我們損傷一半血,不行了,要撤了,不然要死了(哈哈,這裏都是YY),然後我們就把我們之前的存檔用來恢復,最後再顯示人物血條,我們看運行結果吧。
好吧,這個也是似曾相識對吧,只是內容多了點而已,好了,我們的遊戲存檔也完成了,兩種實現備忘錄的方式完全都沒有用到什麽繼承和接口。。。,下面,我們來說說官方名詞。
備忘錄模式:在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣可以在以後將對象恢復到原先保存的狀態,它是一種對象行為模式,其別名為Token。
充血模式:領域對象中包含屬性和業務邏輯的
貧血模式:領域對象中只包含屬性,不包含業務邏輯的
設計模式----備忘錄模式