面向對象編程思想-備忘錄模式
阿新 • • 發佈:2017-08-26
使用 存儲 exc 進度 通過 今天 time program tor
一、引言
上篇博文中我們分享了訪問者模式,訪問者模式是把作用於數據結構上的操作封裝到訪問者類中,使得數據結構與操作分離。今天我們要學習的備忘錄模式與命令模式有點相似,不同的是,命令模式保存的是發起人的具體命令(命令對應行為),而備忘錄模式保存的是發起人的狀態(狀態對應數據內部結構,如屬性)。下面請看今天要學習的訪問者模式
二、備忘錄模式
定義:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可將該對象恢復到原先保存的狀態
下面是備忘錄模式的結構圖:
下面是備忘錄模式代碼demo:
//發起人 class Originator {View Codeprivate string state; public string State { get { return state; } set { state = value; } } //通過實例化備忘錄 保存狀態 public Memento CreateMemento() { return new Memento(state); } //將備忘錄中狀態恢復給發起人 public voidSetMemento(Memento memento) { this.state = memento.State; } public void Show() { Console.WriteLine($"當前state為{State}"); } } //備忘錄類 class Memento { private string state; public Memento(string state) {this.state = state; } public string State { get { return state; } } } //管理者類,負責保存備忘錄 class Caretaker { private Memento memento; public Memento Memento { get { return memento; } set { memento = value; } } } class Program { static void Main(string[] args) { //創建發起人 (修改狀態前) Originator originator = new Originator(); originator.State = "我現在感覺很充實"; originator.Show(); //保存狀態 由於封裝在Memento中,因此客戶端並不知道保存了哪些具體的發起人數據 Caretaker caretaker = new Caretaker(); caretaker.Memento = originator.CreateMemento(); //修改狀態 originator.State = "稍微有一點點的餓"; originator.Show(); //恢復狀態 originator.SetMemento(caretaker.Memento); originator.Show(); Console.Read(); } }
分析:把保存狀態的細節封裝到Memento中,這樣哪天更改保存的細節也不會影響客戶端。使用備忘錄模式可以將復雜對象的內部信息對其他對象屏蔽起來。當角色狀態改變時,有可能這個狀態無效,可以使用暫時存儲的備忘錄將狀態復原。
下面是多狀態多備份備忘錄實例:
//遊戲進度類 class GameState { //生命力 public string Vitality { get; set; } //攻擊力 public string Attackpower { get; set; } //防禦力 public string Defense { get; set; } } //遊戲發起人 class GamePlayer { public List<GameState> LstGameState { get; set; } public GamePlayer(List<GameState> lstGameState) { this.LstGameState = lstGameState; } //創建備忘錄,將要保存的遊戲進度列表導入備忘錄 public GameMemento CreateGameMemento() { return new GameMemento(new List<GameState>(this.LstGameState)); } //將備忘錄中數據備份導入遊戲進度列表 public void SetGameMemento(GameMemento gameMemento) { if (gameMemento != null) { this.LstGameState = gameMemento.LstGameStateBak; } } public void Show() { Console.WriteLine($"遊戲保存了{LstGameState.Count}個進度,分別是"); foreach (GameState gameState in LstGameState) { Console.WriteLine($"生命力{gameState.Vitality},攻擊力{gameState.Attackpower},防禦力{gameState.Defense}"); } } } //備忘錄 class GameMemento { public List<GameState> LstGameStateBak { get; set; } public GameMemento(List<GameState> lstGameState) { this.LstGameStateBak = lstGameState; } } class GameCaretaker { //使用多個備忘錄來儲存備份點 public Dictionary<string,GameMemento> DicGameMemento { get; set; } public GameCaretaker() { DicGameMemento = new Dictionary<string, GameMemento>(); } } class Program { static void Main(string[] args) { List<GameState> lstGameState = new List<GameState>() { new GameState(){Vitality="100",Attackpower="100",Defense="100"}, new GameState(){Vitality="80",Attackpower="80",Defense="80"}, new GameState(){Vitality="50",Attackpower="50",Defense="50"} }; GamePlayer gamePlayer = new GamePlayer(lstGameState); gamePlayer.Show(); //創建備忘錄並保存進度 GameCaretaker gameCaretaker = new GameCaretaker(); gameCaretaker.DicGameMemento.Add(DateTime.Now.ToString(),gamePlayer.CreateGameMemento()); //移除最後一個遊戲進度 gamePlayer.LstGameState.RemoveAt(2); gamePlayer.Show(); Thread.Sleep(1000); //第二次備份 gameCaretaker.DicGameMemento.Add(DateTime.Now.ToString(), gamePlayer.CreateGameMemento()); //恢復到指定進度 var keyCollection = gameCaretaker.DicGameMemento.Keys; foreach (string k in keyCollection) { Console.WriteLine($"key={k}"); } while (true) { Console.WriteLine("請輸入數字,按關閉鍵退出"); int index = -1; try { index = Int32.Parse(Console.ReadLine()); } catch (Exception) { Console.WriteLine("輸入的字符格式不正確"); continue; } GameMemento gameMemento = null; if(index>-1&& index< gamePlayer.LstGameState.Count && gameCaretaker.DicGameMemento.TryGetValue(keyCollection.ElementAt(index),out gameMemento)) { gamePlayer.SetGameMemento(gameMemento); gamePlayer.Show(); } else { Console.WriteLine("索引超出界限"); } } } }View Code
分析:實際應用中,大多情況下用到的是多狀態多備份,如果狀態很大很多,備忘錄對象會很耗內存
優點:
1.如果某個操作錯誤破壞了數據的完整性,可以使用備忘錄模式恢復原來保存的數據
2.備份的狀態保存在發起人之外,這樣發起人就不需要對各個保存的狀態進行管理。
缺點:
1.在實際系統中,可能需要多狀態多備份,對系統資源消耗是比較大的
適用場景:
1.如果系統需要提供回滾操作時,使用備忘錄模式是比較方便的。例如數據庫中事務操作,文本編輯器中的Ctrl+Z撤銷操作
參考:
大話設計模式
http://www.cnblogs.com/zhili/p/MementoPattern.html;
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
面向對象編程思想-備忘錄模式