今天,我們來講備忘錄模式 一、案例: 小伙伴們都玩過單機游戲或者說RPG類的游戲吧,我們在打BOSS之前,需要先存一下檔,以免BOSS打不過從頭再來,好,下麵,我們用簡單的控制台應用程式來描述一下這個場景。 客戶端調用: 好了,我們很好的描述了我們案例中的場景,那下麵,我們看一下我們這段代碼有什麼不 ...
今天,我們來講備忘錄模式
一、案例:
小伙伴們都玩過單機游戲或者說RPG類的游戲吧,我們在打BOSS之前,需要先存一下檔,以免BOSS打不過從頭再來,好,下麵,我們用簡單的控制台應用程式來描述一下這個場景。
1 /// <summary> 2 /// 游戲角色類 3 /// </summary> 4 class GameRole 5 { 6 //生命值 7 private int vit; 8 9 public int Vit 10 { 11 get 12 { 13 return vit; 14 } 15 16 set 17 { 18 vit = value; 19 } 20 } 21 //攻擊力 22 private int atk; 23 public int Def 24 { 25 get 26 { 27 return def; 28 } 29 30 set 31 { 32 def = value; 33 } 34 } 35 private int def; 36 //防禦力 37 public int Atk 38 { 39 get 40 { 41 return atk; 42 } 43 44 set 45 { 46 atk = value; 47 } 48 } 49 //狀態顯示 50 public void StateDisplay() 51 { 52 Console.WriteLine("角色當前狀態:"); 53 Console.WriteLine($"體力:{this.vit}"); 54 Console.WriteLine($"攻擊力:{this.atk}"); 55 Console.WriteLine($"防禦力:{this.def}"); 56 Console.WriteLine(""); 57 } 58 /// <summary> 59 /// 獲取初始狀態 60 /// 數據通常來自本機磁碟或遠程資料庫 61 /// </summary> 62 public void GetInitState() 63 { 64 this.vit = 100; 65 this.atk = 100; 66 this.def = 100; 67 } 68 /// <summary> 69 /// 戰鬥 70 /// 在與Boss大戰後游戲數據損耗為0 71 /// </summary> 72 public void Fight() 73 { 74 this.vit = 0; 75 this.atk = 0; 76 this.def = 0; 77 } 78 }
客戶端調用:
1 public static void Main() 2 { 3 //大戰Boss前 4 GameRole lixiaoyao = new GameRole(); 5 //大戰Boss前,獲得初始角色狀態 6 lixiaoyao.GetInitState(); 7 lixiaoyao.StateDisplay(); 8 9 //保存進度,通過‘游戲角色’的新實例來保存進度 10 GameRole backup = new GameRole(); 11 backup.Vit = lixiaoyao.Vit; 12 backup.Atk = lixiaoyao.Atk; 13 backup.Def = lixiaoyao.Def; 14 15 //大戰Boss 損耗很嚴重 16 lixiaoyao.Fight(); 17 lixiaoyao.StateDisplay(); 18 19 //恢復之前狀態 20 lixiaoyao.Vit = backup.Vit; 21 lixiaoyao.Atk = backup.Atk; 22 lixiaoyao.Def = backup.Def; 23 lixiaoyao.StateDisplay(); 24 Console.ReadKey(); 25 }
好了,我們很好的描述了我們案例中的場景,那下麵,我們看一下我們這段代碼有什麼不足嗎?請看
//保存進度,通過‘游戲角色’的新實例來保存進度 GameRole backup = new GameRole(); backup.Vit = lixiaoyao.Vit; backup.Atk = lixiaoyao.Atk; backup.Def = lixiaoyao.Def;
//恢復之前狀態 lixiaoyao.Vit = backup.Vit; lixiaoyao.Atk = backup.Atk; lixiaoyao.Def = backup.Def; lixiaoyao.StateDisplay();
這兩段代碼在客戶端暴露了細節,客戶端的責任太多了,要知道角色的狀態,還要備份,如果今後需要對角色增加 魔力值 這個屬性,那都是非常麻煩的事情了。
顯然,我們希望將角色的存取狀態細節封存起來,最好是封裝在外部的類當中,以體現職責分離。
面對上述的要求,這裡,我們就需要學習一種新的設計模式了,備忘錄模式。
備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,併在該對象之外保存這個狀態,這樣就可以將對象恢復到原先保存的那個狀態。
好,下麵我們來看一下設計模式的基本結構代碼,需要三個類
1 /// <summary> 2 /// 發起人類 3 /// </summary> 4 class Originator 5 { 6 /// <summary> 7 /// 需要保存的屬性,可以是多個 8 /// </summary> 9 private string state; 10 11 public string State 12 { 13 get 14 { 15 return state; 16 } 17 18 set 19 { 20 state = value; 21 } 22 } 23 /// <summary> 24 /// 創建備忘錄,將當前需要保存的信息導入並實例化出一個Memento對象 25 /// </summary> 26 /// <returns></returns> 27 public Memento CraeteMemento() 28 { 29 return new Memento(state); 30 } 31 32 public void SetMemento(Memento memento) 33 { 34 state = memento.State; 35 } 36 /// <summary> 37 /// 顯示數據 38 /// </summary> 39 public void Show() 40 { 41 Console.WriteLine($"State={state}"); 42 } 43 } 44 /// <summary> 45 /// 備忘錄類 46 /// </summary> 47 class Memento 48 { 49 private string state; 50 /// <summary> 51 /// 構造方法,將相關數據導入 52 /// </summary> 53 /// <param name="state"></param> 54 public Memento(string state) 55 { 56 this.state = state; 57 } 58 /// <summary> 59 /// 需要保存的數據屬性,可以是多個 60 /// </summary> 61 public string State 62 { 63 get { return state; } 64 } 65 } 66 /// <summary> 67 /// 管理者 68 /// </summary> 69 class Caretaker 70 { 71 /// <summary> 72 /// 屬性,得到或設置備忘錄 73 /// </summary> 74 private Memento memento; 75 76 internal Memento Memento 77 { 78 get 79 { 80 return memento; 81 } 82 83 set 84 { 85 memento = value; 86 } 87 } 88 }
客戶端調用:
1 public static void Main() 2 { 3 //Originator 初始狀態,狀態屬性為”On“ 4 Originator o = new Originator(); 5 o.State = "On"; 6 o.Show(); 7 8 //保存狀態時,由於有了很好的封裝,可以隱藏Originator的實現細節 9 Caretaker c = new Caretaker(); 10 c.Memento = o.CraeteMemento(); 11 12 //改變Originator狀態為”Off“ 13 o.State = "Off"; 14 o.Show(); 15 16 //恢複原始狀態 17 o.SetMemento(c.Memento); 18 o.Show(); 19 Console.ReadKey(); 20 }
好,我們就用備忘錄模式來寫一下我們案例中的代碼
1 /// <summary> 2 /// 游戲角色類(發起者) 3 /// </summary> 4 class GameRole 5 { 6 //生命值 7 private int vit; 8 9 public int Vit 10 { 11 get 12 { 13 return vit; 14 } 15 16 set 17 { 18 vit = value; 19 } 20 } 21 //攻擊力 22 private int atk; 23 public int Def 24 { 25 get 26 { 27 return def; 28 } 29 30 set 31 { 32 def = value; 33 } 34 } 35 private int def; 36 //防禦力 37 public int Atk 38 { 39 get 40 { 41 return atk; 42 } 43 44 set 45 { 46 atk = value; 47 } 48 } 49 //狀態顯示 50 public void StateDisplay() 51 { 52 Console.WriteLine("角色當前狀態:"); 53 Console.WriteLine($"體力:{this.vit}"); 54 Console.WriteLine($"攻擊力:{this.atk}"); 55 Console.WriteLine($"防禦力:{this.def}"); 56 Console.WriteLine(""); 57 } 58 /// <summary> 59 /// 獲取初始狀態 60 /// 數據通常來自本機磁碟或遠程資料庫 61 /// </summary> 62 public void GetInitState() 63 { 64 this.vit = 100; 65 this.atk = 100; 66 this.def = 100; 67 } 68 /// <summary> 69 /// 戰鬥 70 /// 在與Boss大戰後游戲數據損耗為0 71 /// </summary> 72 public void Fight() 73 { 74 this.vit = 0; 75 this.atk = 0; 76 this.def = 0; 77 } 78 /// <summary> 79 /// 保存角色狀態 80 /// </summary> 81 /// <returns></returns> 82 public RoleStateMemtento SaveState() 83 { 84 return new RoleStateMemtento(vit, atk, def); 85 } 86 /// <summary> 87 /// 恢復角色狀態 88 /// </summary> 89 /// <param name="memento"></param> 90 public void RecoverState(RoleStateMemtento memento) 91 { 92 this.vit = memento.Vit; 93 this.atk = memento.Atk; 94 this.def = memento.Def; 95 } 96 } 97 /// <summary> 98 /// 角色狀態儲存箱(備忘錄) 99 /// </summary> 100 class RoleStateMemtento 101 { 102 private int vit; 103 private int atk; 104 private int def; 105 106 public int Vit 107 { 108 get 109 { 110 return vit; 111 } 112 113 set 114 { 115 vit = value; 116 } 117 } 118 119 public int Atk 120 { 121 get 122 { 123 return atk; 124 } 125 126 set 127 { 128 atk = value; 129 } 130 } 131 132 public int Def 133 { 134 get 135 { 136 return def; 137 } 138 139 set 140 { 141 def = value; 142 } 143 } 144 /// <summary> 145 /// 將生命力,攻擊力,防禦力 存入狀態存儲箱對象中 146 /// </summary> 147 /// <param name="vit"></param> 148 /// <param name="atk"></param> 149 /// <param name="def"></param> 150 public RoleStateMemtento(int vit, int atk, int def) 151 { 152 this.vit = vit; 153 this.atk = atk; 154 this.def = def; 155 } 156 } 157 /// <summary> 158 /// 管理者 159 /// </summary> 160 class RoleStateCaretaker 161 { 162 private RoleStateMemtento memento; 163 164 internal RoleStateMemtento Memento 165 { 166 get 167 { 168 return memento; 169 } 170 171 set 172 { 173 memento = value; 174 } 175 } 176 }
客戶端調用:
1 public static void Main() 2 { 3 //大戰Boss前 4 //游戲角色初始狀態,三項指標都為100 5 GameRole lixiaoyao = new GameRole(); 6 lixiaoyao.GetInitState(); 7 lixiaoyao.StateDisplay(); 8 9 //保存進度 10 //保存進度時,由於封裝在Memento中,因此,我們並不知道保存了哪些具體的角色數據 11 RoleStateCaretaker stateAdmin = new RoleStateCaretaker(); 12 stateAdmin.Memento = lixiaoyao.SaveState(); 13 14 //大戰Boss,損耗嚴重 15 //三項指標都為0,GameOver了。 16 lixiaoyao.Fight(); 17 lixiaoyao.StateDisplay(); 18 19 //恢復之前狀態 20 lixiaoyao.RecoverState(stateAdmin.Memento); 21 lixiaoyao.StateDisplay(); 22 Console.ReadKey(); 23 }
好了,今天備忘錄模式就講到這裡,下一篇博文,我們講 組合模式
本系列將持續更新,喜歡的小伙伴可以點一下關註和推薦,謝謝大家的支持