備忘錄模式(17)

来源:http://www.cnblogs.com/xiaomowang/archive/2017/02/07/6372887.html
-Advertisement-
Play Games

今天,我們來講備忘錄模式 一、案例: 小伙伴們都玩過單機游戲或者說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         }

好了,今天備忘錄模式就講到這裡,下一篇博文,我們講 組合模式


本系列將持續更新,喜歡的小伙伴可以點一下關註和推薦,謝謝大家的支持


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、指針的四個關鍵概念1、指針的類型2、指針指向的類型3、指針的值,也就是指針指向的地址4、指針自己所占用的記憶體空間註意:指針變數所存的內容就是記憶體的地址編號!例如:int **pp = NULL;1、指針的類型是 int **2、指針指向的類型 int *3、指針的值為NULL4、指針自己所站記憶體 ...
  • 一:語法和語句 # :註釋 \ : 轉譯回車,繼續上一行,在一行語句較長的情況下可以使用其來切分成多行,因其可讀性差所以不建議使用 ; : 將兩個語句連接到一行,可讀性差,不建議使用 : : 將代碼的頭和體分開 語句(代碼塊)用縮進方式體現不同的代碼級別,建議採用4個空格(不要使用tab) pyth ...
  • [TOC] 2.2.7 新的型別轉換操作符(Type Conversion Operators) 1. static_cast 將一個值以符合邏輯的方式轉型。這可看做是“利用原值重建一個臨時對象,併在設立初值時使用型別轉換”。 3. const_cast 設定或去除型別的常數性,亦可去除volati ...
  • 原文 http://www.cnblogs.com/selene/p/4607004.html 一:SqlMapConfig.xml配置文件的內容和配置順序如下 二:properties屬性 作用:將數據連接單獨配置在db.properties中,只需要在SqlMapConfig.xml中載入db. ...
  • 現象 有同事的java系統運行一段時間後發生請求阻塞的情況(返回504),從僅有的記憶體dump文件看,大部分線程都阻塞在了一個本地緩存(jodd cache)的讀鎖上了(ReentrantReadWriteLock$ReadLock.lock)。 排查過程 階段一 本能的反應應該是寫鎖被占用了才會出 ...
  • 打開終端,輸入Python,用print列印"Holle,world" 輸出 Holle,world #print "Holle,world" ...
  • 一:漢化框架 框架漢化在這裡設置,如果不生效,前臺後臺的配置文件都設置下應該就可以了 二:漢化表單 漢化表單,直接在模型層設置,例如: 原來的聯繫我們表單 漢化後: 】 這種漢化在哪裡修改呢?其實是設置屬性標簽,設置位置在模型層 代碼如下 設置位置截圖 ...
  • 一、 面向對象,這個對象到底是什麼? 這個對象不是C#中的實例,C#中我們把一個類的實例也叫做對象,這種對象嚴格的說應該是面向對象的編程實現(OOP)中的對象,面向對象編程,也不是面向類的實例編程。對象的定義是人們要進行研究的任何事物,從最簡單的整數到複雜的飛機等均可看作對象,它不僅能表示具體的事物 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...