結構
UML.png
模式的組成 環境類(Context): 定義客戶感興趣的接口。維護一個ConcreteState子類的實例,這個實例定義當前狀態。 抽象狀態類(State): 定義一個接口以封裝與Context的一個特定狀態相關的行爲。 具體狀態類(ConcreteState): 每一子類實現一個與Context的一個狀態相關的行爲。
本文狀態模式的例子使用我們生活中的交通信號燈的例子。交通信號燈一共具有三種狀態,紅燈,綠燈,黃燈,在這三種狀態之間相互切換。如果讓我們做一個demo,得到不同的狀態時的信號燈顏色,最簡單的寫法應該是如下
if (light=='紅燈') { Console.WriteLine("紅燈"); }else if (light=='綠燈') { Console.WriteLine("綠燈"); } else { Console.WriteLine("黃燈"); }
這樣的寫法通俗易懂,但是同時也存在着很大的問題。所有的 業務邏輯都在上端被定義,如果某一天業務邏輯修改了或者新增了呢,我們就要添加新的if條件,因爲邏輯的高度集成,不可避免的bug就有可能觸發,這是很不友好的,所以這樣的方式實不可取的。
因爲這一章節介紹的是狀態模式,所以我們採用此方式來進行設計,其他的方式LZ也試過,也可以,不過如果是不同的狀態之間帶着關聯,且不同狀態擁有不同行爲的,推薦狀態模式,廢話不多話,開始Lu代碼
上面我們說到狀態模式的組成分爲三個: 環境類(Context) 抽象狀態類(State) 具體狀態類(ConcreteState) 就算有每一個的解釋,我們還是不能很好的理解意思,接下來我用一個通俗的方式來說明。 還是用信號燈的例子來作爲參考
抽象狀態類,就是信號燈抽象類,裏面包含顏色的顯示接口 具體狀態類,就是三個顏色的信號燈,繼承信號燈抽象類,重載顏色顯示接口 環境類,就是信號燈,負責切換不同信號燈狀態
大同小異,如果我們的對象是電梯,我們是不是也可以 用同樣的道理推斷出來。接下來讓我們對三個組成進行編碼
信號燈抽象類
public enum LightColor { Green = 0, Yellow = 1, Red = 2 } /// <summary> /// 燈基類 /// </summary> public abstract class LightBase { public LightColor Color { get; set; } /// <summary> /// 展示燈狀態 /// </summary> public abstract void Show(); /// <summary> /// 切換燈顏色 /// </summary> public abstract void Turn(); /// <summary> /// 切換上下文 /// </summary> public abstract void TurnContext(LightContext context); }
具體狀態類
三種顏色的信號燈實現
public class GreenLight:LightBase { public override void Show() { Console.WriteLine("綠燈"); } public override void Turn() { this.Color = LightColor.Yellow; } public override void TurnContext(LightContext context) { context.LigthBase = new YellowLight(); } } public class RedLight : LightBase { public override void Show() { Console.WriteLine("紅燈"); } public override void Turn() { this.Color = LightColor.Green; } public override void TurnContext(LightContext context) { context.LigthBase = new GreenLight(); } } public class YellowLight : LightBase { public override void Show() { Console.WriteLine("黃燈"); } public override void Turn() { this.Color = LightColor.Red; } public override void TurnContext(LightContext context) { context.LigthBase = new RedLight(); } }
環境類
信號燈控制
/// <summary> /// 燈控制上下文 /// </summary> public class LightContext { public LightBase LigthBase; public LightContext(LightBase lightBase) { this.LigthBase = lightBase; } /// <summary> /// 展示當前燈顏色 /// </summary> public void Show() { this.LigthBase.Show(); } /// <summary> /// 切換到一下個燈 /// </summary> public void Turn() { this.LigthBase.TurnContext(this); } }
上面的代碼,其實是對原來的一個簡單的修改,將邏輯從三層if中分離出來,不同顏色的類完成自己的功能,實現了業務邏輯的分離。
輸出
public class StateShow { public static void Show() { LightBase greeBase = new GreenLight(); LightContext context = new LightContext(greeBase); context.Show(); context.Turn(); context.Show(); context.Turn(); context.Show(); context.Turn(); Console.Read(); } }
show.png
重要點解析
抽象基類中重要的一個接口 public abstract void TurnContext(LightContext context); 在具體抽象類中我們可以看到對應的實現,以YellowLight(黃燈狀態舉例) public override void TurnContext(LightContext context) { context.LigthBase = new RedLight(); } 通過實現接口,我們將傳遞的上下文進行更改。這麼一來大概的意思就出來了,例如我們現在是綠燈狀態,類就是GreenLight,對應的行爲是Show(),如果我們想要切換到下一個狀態,我們只需要將環境上下文進行切換,例如我們切換到紅燈狀態,那我們就可以操作紅燈的行爲Show()。 接下去就是環境類的說明 /// <summary> /// 燈控制上下文 /// </summary> public class LightContext { public LightBase LigthBase; public LightContext(LightBase lightBase) { this.LigthBase = lightBase; } /// <summary> /// 展示當前燈顏色 /// </summary> public void Show() { this.LigthBase.Show(); } /// <summary> /// 切換到一下個燈 /// </summary> public void Turn() { this.LigthBase.TurnContext(this); } }
環境類的實現也很簡單,我們定義了一個內部的成員變量(LightBase),因爲LightBase是所有狀態燈的基類,所以我們可以在LightContext上下文內部定義操作LigthBase的方法,也就是Show。 Turn方法的實現可能有些人一下子看不懂,這個實現還是有點意思的。當前LightBase執行TurnContext(參數),參數是他自身。 舉一個紅燈變綠燈的例子也就能看懂了
LightContext context=new LightContext(new RedLight()); 默認是紅燈,我們調用 context.Turn(); 執行的其實是RedLigth 的TurnContext方法 public override void TurnContext(LightContext context) { context.LigthBase = new GreenLight(); }
解析.png