狀態模式(State)

結構

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章