C#設計模式(19)——狀態者模式(State Pattern)

原文:C#設計模式(19)——狀態者模式(State Pattern)

一、引言

  在上一篇文章介紹到可以使用狀態者模式和觀察者模式來解決中介者模式存在的問題,在本文中將首先通過一個銀行賬戶的例子來解釋狀態者模式,通過這個例子使大家可以對狀態者模式有一個清楚的認識,接著,再使用狀態者模式來解決上一篇文章中提出的問題。

二、狀態者模式的介紹

  每個對象都有其對應的狀態,而每個狀態又對應一些相應的行為,如果某個對象有多個狀態時,那么就會對應很多的行為。那么對這些狀態的判斷和根據狀態完成的行為,就會導致多重條件語句,并且如果添加一種新的狀態時,需要更改之前現有的代碼。這樣的設計顯然違背了開閉原則。狀態模式正是用來解決這樣的問題的。狀態模式將每種狀態對應的行為抽象出來成為單獨新的對象,這樣狀態的變化不再依賴于對象內部的行為。

2.1 狀態者模式的定義

  上面對狀態模式做了一個簡單的介紹,這里給出狀態模式的定義。

  狀態模式——允許一個對象在其內部狀態改變時自動改變其行為,對象看起來就像是改變了它的類。

2.2 狀態者模式的結構

  既然狀態者模式是對已有對象的狀態進行抽象,則自然就有抽象狀態者類和具體狀態者類,而原來已有對象需要保存抽象狀態者類的引用,通過調用抽象狀態者的行為來改變已有對象的行為。經過上面的分析,狀態者模式的結構圖也就很容易理解了,具體結構圖如下圖示。

  

  從上圖可知,狀態者模式涉及以下三個角色:

  • Account類:維護一個State類的一個實例,該實例標識著當前對象的狀態。
  • State類:抽象狀態類,定義了一個具體狀態類需要實現的行為約定。
  • SilveStater、GoldState和RedState類:具體狀態類,實現抽象狀態類的每個行為。

2.3 狀態者模式的實現

  下面,就以銀行賬戶的狀態來實現下狀態者模式。銀行賬戶根據余額可分為RedState、SilverState和GoldState。這些狀態分別代表透支賬號,新開賬戶和標準賬戶。賬號余額在【-100.0,0.0】范圍表示處于RedState狀態,賬號余額在【0.0 , 1000.0】范圍表示處于SilverState,賬號在【1000.0, 100000.0】范圍表示處于GoldState狀態。下面以這樣的一個場景實現下狀態者模式,具體實現代碼如下所示:

  1 namespace StatePatternSample
  2 {
  3     public class Account
  4     {
  5         public State State {get;set;}
  6         public string Owner { get; set; }
  7         public Account(string owner)
  8         {
  9             this.Owner = owner;
 10             this.State = new SilverState(0.0, this);
 11         }
 12 
 13         public double Balance { get {return State.Balance; }} // 余額
 14         // 存錢
 15         public void Deposit(double amount)
 16         {
 17             State.Deposit(amount);
 18             Console.WriteLine("存款金額為 {0:C}——", amount);
 19             Console.WriteLine("賬戶余額為 =:{0:C}", this.Balance);
 20             Console.WriteLine("賬戶狀態為: {0}", this.State.GetType().Name);
 21             Console.WriteLine();
 22         }
 23 
 24         // 取錢
 25         public void Withdraw(double amount)
 26         {
 27             State.Withdraw(amount);
 28              Console.WriteLine("取款金額為 {0:C}——",amount);
 29             Console.WriteLine("賬戶余額為 =:{0:C}", this.Balance);
 30             Console.WriteLine("賬戶狀態為: {0}", this.State.GetType().Name);
 31             Console.WriteLine();
 32         }
 33 
 34         // 獲得利息
 35         public void PayInterest()
 36         {
 37             State.PayInterest();
 38             Console.WriteLine("Interest Paid --- ");
 39             Console.WriteLine("賬戶余額為 =:{0:C}", this.Balance);
 40             Console.WriteLine("賬戶狀態為: {0}", this.State.GetType().Name);
 41             Console.WriteLine();
 42         }
 43     }
 44 
 45     // 抽象狀態類
 46     public abstract class State
 47     {
 48         // Properties
 49         public Account Account { get; set; }
 50         public double Balance { get; set; } // 余額
 51         public double Interest { get; set; } // 利率
 52         public double LowerLimit { get; set; } // 下限
 53         public double UpperLimit { get; set; } // 上限
 54 
 55         public abstract void Deposit(double amount); // 存款
 56         public abstract void Withdraw(double amount); // 取錢
 57         public abstract void PayInterest(); // 獲得的利息
 58     }
 59 
 60     // Red State意味著Account透支了
 61     public class RedState : State
 62     {
 63         public RedState(State state)
 64         {
 65             // Initialize
 66             this.Balance = state.Balance;
 67             this.Account = state.Account;
 68             Interest = 0.00;
 69             LowerLimit = -100.00;
 70             UpperLimit = 0.00;
 71         }
 72 
 73         // 存款
 74         public override void Deposit(double amount)
 75         {
 76             Balance += amount;
 77             StateChangeCheck();
 78         }
 79         // 取錢
 80         public override void Withdraw(double amount)
 81         {
 82             Console.WriteLine("沒有錢可以取了!");
 83         }
 84 
 85         public override void PayInterest()
 86         {
 87             // 沒有利息
 88         }
 89 
 90         private void StateChangeCheck()
 91         {
 92             if (Balance > UpperLimit)
 93             {
 94                 Account.State = new SilverState(this);
 95             }
 96         }
 97     }
 98 
 99     // Silver State意味著沒有利息得
100     public class SilverState :State
101     {
102         public SilverState(State state)
103             : this(state.Balance, state.Account)
104         { 
105         }
106 
107         public SilverState(double balance, Account account)
108         {
109             this.Balance = balance;
110             this.Account = account;
111             Interest = 0.00;
112             LowerLimit = 0.00;
113             UpperLimit = 1000.00;
114         }
115 
116         public override void Deposit(double amount)
117         {
118             Balance += amount;
119             StateChangeCheck();
120         }
121         public override void Withdraw(double amount)
122         {
123             Balance -= amount;
124             StateChangeCheck();
125         }
126 
127         public override void PayInterest()
128         {
129             Balance += Interest * Balance;
130             StateChangeCheck();
131         }
132 
133         private void StateChangeCheck()
134         {
135             if (Balance < LowerLimit)
136             {
137                 Account.State = new RedState(this);
138             }
139             else if (Balance > UpperLimit)
140             {
141                 Account.State = new GoldState(this);
142             }
143         }     
144     }
145 
146     // Gold State意味著有利息狀態
147     public class GoldState : State
148     {
149         public GoldState(State state)
150         {
151             this.Balance = state.Balance;
152             this.Account = state.Account;
153             Interest = 0.05;
154             LowerLimit = 1000.00;
155             UpperLimit = 1000000.00;
156         }
157         // 存錢
158         public override void Deposit(double amount)
159         {
160             Balance += amount;
161             StateChangeCheck();
162         }
163         // 取錢
164         public override void Withdraw(double amount)
165         {
166             Balance -= amount;
167             StateChangeCheck();
168         }
169         public override void PayInterest()
170         {
171             Balance += Interest * Balance;
172             StateChangeCheck();
173         }
174 
175         private void StateChangeCheck()
176         {
177             if (Balance < 0.0)
178             {
179                 Account.State = new RedState(this);
180             }
181             else if (Balance < LowerLimit)
182             {
183                 Account.State = new SilverState(this);
184             }
185         }
186     }
187 
188     class App
189     {
190         static void Main(string[] args)
191         {
192             // 開一個新的賬戶
193             Account account = new Account("Learning Hard");
194 
195             // 進行交易
196             // 存錢
197             account.Deposit(1000.0);
198             account.Deposit(200.0);
199             account.Deposit(600.0);
200 
201             // 付利息
202             account.PayInterest();
203 
204             // 取錢
205             account.Withdraw(2000.00);
206             account.Withdraw(500.00);
207             
208             // 等待用戶輸入
209             Console.ReadKey();
210         }
211     }
212 }

  上面代碼的運行結果如下圖所示:

  從上圖可以發現,進行存取款交易,會影響到Account內部的狀態,由于狀態的改變,從而影響到Account類行為的改變,而且這些操作都是發生在運行時的。

三、應用狀態者模式完善中介者模式方案

  在上一篇博文中,我曾介紹到中介者模式存在的問題,詳細的問題描述可以參考上一篇博文。下面利用觀察者模式和狀態者模式來完善中介者模式,具體的實現代碼如下所示:

  1  // 抽象牌友類
  2     public abstract class AbstractCardPartner
  3     {
  4         public int MoneyCount { get; set; }
  5 
  6         public AbstractCardPartner()
  7         {
  8             MoneyCount = 0;
  9         }
 10 
 11         public abstract void ChangeCount(int Count, AbstractMediator mediator);
 12     }
 13 
 14     // 牌友A類
 15     public class ParterA : AbstractCardPartner
 16     {
 17         // 依賴與抽象中介者對象
 18         public override void ChangeCount(int Count, AbstractMediator mediator)
 19         {
 20             mediator.ChangeCount(Count);
 21         }
 22     }
 23 
 24     // 牌友B類
 25     public class ParterB : AbstractCardPartner
 26     {
 27         // 依賴與抽象中介者對象
 28         public override void ChangeCount(int Count, AbstractMediator mediator)
 29         {
 30             mediator.ChangeCount(Count);
 31         }
 32     }
 33 
 34     // 抽象狀態類
 35     public abstract class State
 36     {
 37         protected AbstractMediator meditor;
 38         public abstract void ChangeCount(int count);
 39     }
 40 
 41     // A贏狀態類
 42     public class AWinState : State
 43     {
 44         public AWinState(AbstractMediator concretemediator)
 45         {
 46             this.meditor = concretemediator;
 47         }
 48 
 49         public override void ChangeCount(int count)
 50         {
 51             foreach (AbstractCardPartner p in meditor.list)
 52             {
 53                 ParterA a = p as ParterA;
 54                 // 
 55                 if (a != null)
 56                 {
 57                     a.MoneyCount += count;
 58                 }
 59                 else
 60                 {
 61                     p.MoneyCount -= count;
 62                 }
 63             }
 64         }
 65     }
 66 
 67     // B贏狀態類
 68     public class BWinState : State
 69     {
 70         public BWinState(AbstractMediator concretemediator)
 71         {
 72             this.meditor = concretemediator;
 73         }
 74 
 75         public override void ChangeCount(int count)
 76         {
 77             foreach (AbstractCardPartner p in meditor.list)
 78             {
 79                 ParterB b = p as ParterB;
 80                 // 如果集合對象中時B對象,則對B的錢添加
 81                 if (b != null)
 82                 {
 83                     b.MoneyCount += count;
 84                 }
 85                 else
 86                 {
 87                     p.MoneyCount -= count;
 88                 }
 89             }
 90         }
 91     }
 92 
 93     // 初始化狀態類
 94     public class InitState : State
 95     {
 96         public InitState()
 97         {
 98             Console.WriteLine("游戲才剛剛開始,暫時還有玩家勝出");
 99         }
100 
101         public override void ChangeCount(int count)
102         {
103             // 
104             return;
105         }
106     }
107 
108     // 抽象中介者類
109     public abstract class AbstractMediator
110     {
111         public List<AbstractCardPartner> list = new List<AbstractCardPartner>();
112 
113         public State State { get; set; }
114 
115         public AbstractMediator(State state)
116         {
117             this.State = state;
118         }
119 
120         public void Enter(AbstractCardPartner partner)
121         {
122             list.Add(partner);
123         }
124 
125         public void Exit(AbstractCardPartner partner)
126         {
127             list.Remove(partner);
128         }
129 
130         public void ChangeCount(int count)
131         {
132             State.ChangeCount(count);
133         }
134     }
135 
136     // 具體中介者類
137     public class MediatorPater : AbstractMediator
138     {
139         public MediatorPater(State initState)
140             : base(initState)
141         { }
142     }
143 
144     class Program
145     {
146         static void Main(string[] args)
147         {
148             AbstractCardPartner A = new ParterA();
149             AbstractCardPartner B = new ParterB();
150             // 初始錢
151             A.MoneyCount = 20;
152             B.MoneyCount = 20;
153 
154             AbstractMediator mediator = new MediatorPater(new InitState());
155 
156             // A,B玩家進入平臺進行游戲
157             mediator.Enter(A);
158             mediator.Enter(B);
159 
160             // A贏了
161             mediator.State = new AWinState(mediator);
162             mediator.ChangeCount(5);
163             Console.WriteLine("A 現在的錢是:{0}", A.MoneyCount);// 應該是25
164             Console.WriteLine("B 現在的錢是:{0}", B.MoneyCount); // 應該是15
165 
166             // B 贏了
167             mediator.State = new BWinState(mediator);
168             mediator.ChangeCount(10);
169             Console.WriteLine("A 現在的錢是:{0}", A.MoneyCount);// 應該是25
170             Console.WriteLine("B 現在的錢是:{0}", B.MoneyCount); // 應該是15
171             Console.Read();
172         }
173     }
View Code

四、狀態者模式的應用場景

?  在以下情況下可以考慮使用狀態者模式。

  • 當一個對象狀態轉換的條件表達式過于復雜時可以使用狀態者模式。把狀態的判斷邏輯轉移到表示不同狀態的一系列類中,可以把復雜的判斷邏輯簡單化。
  • 當一個對象行為取決于它的狀態,并且它需要在運行時刻根據狀態改變它的行為時,就可以考慮使用狀態者模式。

五、狀態者模式的優缺點

?  狀態者模式的主要優點是:

  • 將狀態判斷邏輯每個狀態類里面,可以簡化判斷的邏輯。
  • 當有新的狀態出現時,可以通過添加新的狀態類來進行擴展,擴展性好。

  狀態者模式的主要缺點是:

  • 如果狀態過多的話,會導致有非常多的狀態類,加大了開銷。

六、總結

  狀態者模式是對對象狀態的抽象,從而把對象中對狀態復雜的判斷邏輯已到各個狀態類里面,從而簡化邏輯判斷。在下一篇文章將分享我對策略模式的理解。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/453516.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/453516.shtml
英文地址,請注明出處:http://en.pswp.cn/news/453516.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OLTP與OLAP

當今的數據處理大致可以分成兩大類&#xff1a;聯機事務處理OLTP&#xff08;on-line transaction processing&#xff09;、聯機分析處理OLAP&#xff08;On-Line Analytical Processing&#xff09;。OLTP是傳統的關系型數據庫的主要應用&#xff0c;主要是基本的、日常的事務…

揭秘IT人才特點:中美印日四國程序員比較

揭秘IT人才特點&#xff1a;中美印日四國程序員比較 最近以裁判的身份參加了公司舉辦的編程大賽&#xff0c;發現高手云集&#xff0c;對公司內部的程序員能力也有了更深入的了解。我覺得編程能力對程序員而言&#xff0c;雖然很重要&#xff0c;但并不是全部。那么作為一個程…

BaseColumns類的作用

這個類只是提供了兩個字段&#xff0c;一個是"_id"一個是"_count"&#xff0c;便于調用數據庫時導致拼寫錯誤&#xff0c;你也可以擴展它&#xff0c;或者自定義這么個&#xff0c;然后直接調用它的常量名&#xff0c;防止寫sql語句時把列名拼錯 /** Copyr…

java如何限制輸入值_[限制input輸入類型]常用限制input方法

常用限制input的方法1.取消按鈕按下時的虛線框,在input里添加屬性值 hideFocus 或者 HideFocustrueinput type"submit" value"提交" hidefocus"true"2.只讀文本框內容,在input里添加屬性值 readonlyinput type"text" readonly3.防止退…

如何規范 CSS 的命名和書寫

我開始學前端的時候也是對于規范問題頭疼&#xff0c;后來看了網易的NEC規范&#xff0c;驚呼牛逼 NEC : 更好的CSS樣式解決方案 只遵循橫向順序即可&#xff0c;先顯示定位布局類屬性&#xff0c;后盒模型等自身屬性&#xff0c;最后是文本類及修飾類屬性。 →顯示屬性自身屬性…

app性能測試指標

性能測試在軟件的質量保證中起著重要的作用&#xff0c;它包括的測試內容豐富多樣。中國軟件評測中心將性能測試概括為三個方面&#xff1a;應用在客戶端性能的測試、應用在網絡上性能的測試和應用在服務器端性能的測試。通常情況下&#xff0c;三方面有效、合理的結合&#xf…

《學做程序經理》完整版

文/Joel Spolsky 譯/羅小平 指派一名優秀的程序經理&#xff0c;是團隊產出優秀軟件的重要前提之一。你的團隊里可能沒有這樣的人&#xff0c;其實絕大多數團隊都沒有。 Charles Simonyi&#xff0c;這位曾與MarthaStewart&#xff08;譯者注&#xff1a;美國女富豪&#…

java工程mvn引用jar_maven 項目加載本地JAR

將jar安裝到本地的maven倉庫1.首先確定本地有maven環境。2.安裝本地jar模板&#xff1a;mvn install:install-file -Dfile -DgroupId -DartifactId -Dversion -Dpackaging示例&#xff1a;mvn install:install-file -DfileF:\jave-ffmpegjave-1.0.2.jar -DgroupIdffmpegjave -D…

compress()方法

boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream) 把位圖的壓縮信息寫入到一個指定的輸出流中。如果返回true&#xff0c;可以通過傳遞一個相應的輸出流到BitmapFactory.decodeStream()來重構該位圖。注意&#xff1a;并非所有的格式都直接支…

token的三點注意項

token的安全是極度重要的 1&#xff1a;token的唯一性&#xff0c; 它代表著來自某應用系統用戶的一次成功登錄。我們可以利用java util包工具直接生成一個32位唯一字符串來實現。 String token UUID.randomUUID().toString(); 同時&#xff0c;我們定義一個javabean&#xff…

0.1 js復習

1.1 JavaScript的用途 JavaScript用來制作web頁面交互效果&#xff0c;提升用戶體驗。 能夠制作的頁面效果&#xff1a;輪播圖&#xff0c;無限瀑布流&#xff0c;tab切換&#xff0c;定位地圖&#xff0c;表單驗證等。 web前端三層來說&#xff1a; 結構層 HTML 從語義的角度&…

優秀的軟件企業為何倒下?

最近不到一個月&#xff0c;就看到兩家著名公司——SUN公司和Borland公司相繼被收購&#xff0c;引起IT界不小的震動&#xff0c;讓人感慨萬分。在此之前有北電&#xff08;Nortel&#xff09;、摩托羅拉的衰退&#xff0c;再往前有 美國數字設備公司Digital&#xff08;Digita…

python 列表的推導器和內置函數

# 列表的推導式# li []# for i in range(1,11):# li.append(i)# print(li)## lis [i for i in range(1,11)] #列表的推導式# print(lis)#[變量&#xff08;加工后的變量&#xff09; for 變量 i in 可迭代的數據類型】 列表的推導式# li2 []# for i in ran…

Android service 中的stub類

stub是為了方便client&#xff0c;service交互而生成出來的代碼。 AIDL(android 接口描述語言)是一個IDL語言&#xff0c;它可以生成一段代碼&#xff0c;可以使在一個android設備上運行的兩個進程使用內部通信進程進行交互。如果你需要在一個進程中(例如:在一個Activity中)訪…

kafka exporter v0.3.0 發布: Prometheus官方推薦,歡迎試用

2019獨角獸企業重金招聘Python工程師標準>>> 時隔1個半月&#xff0c;kakfa exporter v0.3.0于今日正式發布&#xff0c;歡迎大家試用。 項目地址 Github: https://github.com/danielqsj/kafka_exporter Docker Hub: https://hub.docker.com/r/danielqsj/kafka-expo…

java手動切換成獨立顯卡_JAVA設計模式之調停者模式

在閻宏博士的《JAVA與模式》一書中開頭是這樣描述調停者(Mediator)模式的&#xff1a;調停者模式是對象的行為模式。調停者模式包裝了一系列對象相互作用的方式&#xff0c;使得這些對象不必相互明顯引用。從而使它們可以較松散地耦合。當這些對象中的某些對象之間的相互作用發…

2018.2.8 php實現qq登陸接口

PHP實現QQ登錄的原理和實現過程 2018-02-08 學習與分享 PHP自學中心 第三方登錄&#xff0c;就是使用大家比較熟悉的比如QQ、微信、微博等第三方軟件登錄自己的網站&#xff0c;這可以免去注冊賬號、快速留住用戶的目的&#xff0c;免去了相對復雜的注冊流程。下邊就給大家講一…

關于積累的一點看法

這是vip那邊發表的一篇帖子&#xff0c;今天整理&#xff0c;發現可能有一點代表性&#xff0c;就再發在這里&#xff0c;供各位同學參考。 壇子里有人討論小公司要不要積累框架的問題&#xff0c;有感而發&#xff0c;寫了點自己的看法&#xff0c;一家之言&#xff0c;歡迎拍…

去除vue項目中的#及其ie9兼容性

一、如何去除vue項目中訪問地址的# vue2中在路由配置中添加mode&#xff08;vue-cli創建的項目在src/router/index.js&#xff09; 1 export default new Router({2 mode: history,3 routes: [4 {5 path: /,6 name: menu,7 component: menu,8 …

sendBroadcast與sendStickyBroadcast的區別

前提條件&#xff1a;此處我主要討論兩種廣播在代碼中動態注冊時的一些細節問題。 正常情況下&#xff0c;廣播通常都是執行一次注冊代碼&#xff0c;就會觸發各接收器接收一次&#xff0c;無論是在onCreate里注冊還是onResume里注冊&#xff1a;若在onCreate里注冊&#xff0…