備忘錄模式(Memento),在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣就可以將該對象狀態恢復到原先保存的狀態。 備忘錄模式UML類圖: 由上圖可知,Originator(發起人)類:負責創建一個備忘錄Memento,用以記錄當前時刻它的內部狀態,並可使用備忘錄恢復內部狀態,Originator可根據需要決定Memento存儲Originator的哪些內部狀態 。 Memento(備忘錄):負責存儲Originator對象的內部狀態,並可防止Originator以外的其它對象訪問備忘錄Memento。備忘錄有兩個接口,Caretaker只能看到Memento的窄接口,它只能將備忘錄傳遞給其它對象,Originator看到一個寬接口允許它訪問返回到先前狀態所需的所有數據。 Caretaker(管理者):負責保存好備忘錄Memento,不能對備忘錄的內容進行操作或檢查。 備忘錄模式(Memento)實現: [csharp] using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Memento { /* * 備忘錄Memento類,負責存儲Originator對象的內部狀態, * 並可防止Originator以外的其它對象訪問備忘錄。 */ class Memento { private string state; public Memento(string state)//構造方法將相關數據導入 { this.state = state; } public string getState()//需要保存的數據屬性,可以是多個 { return this.state; } } /* * Originator發起人類,負責創建一個備忘錄Memento, * 用以記錄當前時刻它的內部狀態,並可以使用備忘錄恢復內部狀態。 */ class Originator { private string state;//需要保存屬性可能有多個 public string getState() { return this.state; } public void setState(string state) { this.state = state; } public Memento CreateMemento()//創建備忘錄,將當前需要保存的信息導入並實例化出一個Memento對象 { return new Memento(this.getState()); } public void RecoveryMemento(Memento memento)//恢復備忘錄,將Memento導入並將相關數據恢復 { this.state = memento.getState(); } public void show()//顯示數據 { Console.WriteLine("state:" + this.state); } } /* * Caretaker負責保存好備忘錄Memento */ class Caretaker { private Memento memento; public Memento getMemento()//得到備忘錄 { return this.memento; } public void setMemento(Memento memento)//設置備忘錄 { this.memento = memento; } } } 客戶端: [csharp] using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Memento { class Program { static void Main(string[] args) { Originator o = new Originator(); Console.WriteLine("Originator對象o的初始狀態..."); o.setState("on"); o.show(); Caretaker c = new Caretaker(); /* * 保存狀態時,由於有了很好的封裝,可以隱藏Originator的實現細節 */ c.setMemento(o.CreateMemento()); Console.WriteLine("Originator對象o改變了狀態屬性為“off”..."); o.setState("off"); o.show(); Console.WriteLine("恢復初始狀態..."); o.RecoveryMemento(c.getMemento()); o.show(); Console.Read(); } } } 備忘錄模式總結: (1)使用備忘錄模式,也就是將要保存的細節給封裝在了Memento中,哪一天要更改保存的細節也不用影響客戶端了。 (2)備忘錄模式比較適用於功能比較復雜的,但需要維護或記錄屬性歷史的類,或者需要保存的屬性只是眾多屬性的一小部分時,Originator可以根據保存的Memento信息還原到前一狀態。 (3)如果在某個系統中使用命令模式時,需要實現命令模式的撤銷功能,那麼命令模式可以使用備忘錄模式來存儲可撤銷操作的狀態。 (4)在當角色的狀態改變的時候有可能這個狀態無效,這時,就可以使用暫時存儲起來的備忘錄將狀態復原。 備忘錄模式案例——游戲進度備忘 [csharp] using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MementoExample { class Memento { } //游戲角色類 class GameRole { //生命力 private int vit; //攻擊力 private int atk; //防御力 private int def; public int getVit() { return this.vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return this.atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return this.def; } public void setzdef(int def) { this.def = def; } /*設置初始狀態*/ public void InitState() { this.vit = 100; this.atk = 100; this.def = 100; } /*當前狀態顯示*/ public void ShowState() { Console.WriteLine("角色當前狀態:"); Console.WriteLine("生命力:{0}",this.vit); Console.WriteLine("攻擊力:{0}",this.atk); Console.WriteLine("防御力:{0}",this.def); } /*戰斗*/ public void Fight() { this.vit = 0; this.atk = 0; this.def = 0; } /*保存角色狀態*/ public RoleStateMemento SaveRoleState() { return new RoleStateMemento(this.vit,this.atk,this.def); } /*恢復角色狀態*/ public void RecoveryState(RoleStateMemento rsm) { this.vit = rsm.getVit(); this.atk = rsm.getAtk(); this.def = rsm.getDef(); } } /*角色狀態備忘錄*/ 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 getVit() { return this.vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return this.atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return this.def; } public void setzdef(int def) { this.def = def; } } /*游戲管理者類*/ class RoleStateCaretaker { private RoleStateMemento rsm; public RoleStateMemento getRsm() { return this.rsm; } public void setRsm(RoleStateMemento rsm) { this.rsm = rsm; } } } 客戶端: [csharp] using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MementoExample { class Program { static void Main(string[] args) { //大戰boss前 Console.WriteLine("大戰boss前..."); GameRole gr = new GameRole(); gr.InitState(); gr.ShowState(); //保存進度 RoleStateCaretaker rsc = new RoleStateCaretaker(); rsc.setRsm(gr.SaveRoleState()); //大戰boss,損耗嚴重 Console.WriteLine("大戰boss,損耗嚴重..."); gr.Fight(); gr.ShowState(); //恢復進度 Console.WriteLine("恢復進度..."); gr.RecoveryState(rsc.getRsm()); gr.ShowState(); Console.Read(); } } } 運行結果: