通俗易懂設計模式解析——狀態模式

前言

  今天咱們講的是狀態模式【State Pattern】、這個名字咋一看很差理解,可是仔細一想仍是比較容易的。狀態模式重點關注的是狀態。狀態又牽扯着什麼呢?房屋的狀態暫且能夠分爲出租、簽定合同、退房。那麼出租對應的是什麼呢?出租狀態表明能夠租房。能夠租房是一個行爲了。因此不難理解的是狀態模式關注的是狀態的改變與行爲的變化。html

狀態模式介紹

1、來由

  在軟件系統中,常常狀態的改變影響着行爲的變化。例如房屋狀態是出租既能夠租房、出售既能夠買賣房、不租售意味不可操做。那麼如何避免對象操做和狀態轉換之間出現緊耦合呢?狀態模式將每種狀態對應的行爲抽象出來成爲單獨新的對象,這樣狀態的變化再也不依賴於對象內部的行爲正解決了此問題。設計模式

2、意圖

  容許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。this

3、案例圖

 

4、狀態模式代碼示例

咱們看下案例圖中主要三個部分:spa

環境角色:包含保留了一個具體狀態的實例、給出當前狀態及調用方法。設計

抽象狀態:定義接口、封裝一個狀態相對應的行爲方法。code

具體狀態:實現具體狀態對應的的具體對應行爲。htm

咱們繼續看這個房屋的案例,針對房屋咱們整理這麼一個案例,租房而後簽定合同。合同半年內退房無押金。租房時間達到半年退房可得押金。咱們看下代碼實現吧:對象

 

namespace State_Pattern
{
    /// <summary>
    /// 房屋對象類
    /// </summary>
  public  class StatePattern
    {
        /// <summary>
        /// 房屋Id
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 房屋名稱
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 租房時間/月
        /// </summary>
        public int Time { get; set; }
        /// <summary>
        /// 房屋狀態
        /// </summary>
        public HouseState State { get; set; }
        /// <summary>
        /// 是否退押金
        /// </summary>
        public bool IsDeposit { get; set; }
    }

    /// <summary>
    /// 房屋出租狀態枚舉
    /// </summary>
    public enum HouseState 
    {
        [Description("出租")]
        Lease =1,
        [Description("簽定合同")]
        Leaseed = 2,
        [Description("退房")]
        Deposit = 3, 
    }

    /// <summary>
    /// 環境角色
    /// </summary>
    public class Environmental
    {
        public State _state;

        /// <summary>
        /// 初始化房屋狀態
        /// </summary>
        public Environmental()
        {
            this._state = new LeaseState();
        }

        public StatePattern _statePattern { get; set; }

        /// <summary>
        /// 獲取房屋對象
        /// </summary>
        /// <param name="statePattern"></param>
        public void GetStatePattern(StatePattern statePattern,State state=null)
        {
            _statePattern = statePattern;
            if (state!=null)
            {
                _state =  state;
            }
        }

        /// <summary>
        /// 更改狀態方法
        /// </summary>
        /// <param name="state"></param>
        public void SetState(State state) 
        {
            _state = state;
        }

        public void Show() 
        {
            if (this._statePattern!=null)
            {
                _state.Handle(this);
            }
            else
            {
                Console.WriteLine("無可操做房屋!");
            }
        }
    }

    /// <summary>
    /// 抽象狀態接口
    /// </summary>
    public interface  State 
    {
        void Handle(Environmental environmental);
    }

    /// <summary>
    /// 出租狀態
    /// </summary>
    public class LeaseState : State
    {
        public void Handle(Environmental environmental)
        {
              
            //房屋出租
            if (environmental._statePattern.State==HouseState.Lease)
            {
                Console.WriteLine($"{environmental._statePattern.Name}房屋正在出租!");
                Console.WriteLine("若是以爲能夠的話就簽定租房合同!"); 
                environmental.SetState(new LeaseedState());
                environmental.Show();
            }
        }
    } 

    /// <summary>
    /// 簽定合同狀態
    /// </summary>
    public class LeaseedState : State
    {
        public void Handle(Environmental environmental)
        {
             
            
            //後期辦理退房手續
            if (environmental._statePattern.State == HouseState.Lease)
            {
                Console.WriteLine($"{environmental._statePattern.Name}簽定租房合同!");
                environmental._statePattern.State = HouseState.Leaseed;
                environmental._statePattern.Time = 1;
                environmental.SetState(new DepositState());
                environmental.Show();
            }
        }
    }

 

    /// <summary>
    /// 退房有押金狀態
    /// </summary>
    public class DepositState : State
    {
        public void Handle(Environmental environmental)
        {
            environmental._statePattern.IsDeposit = true;
            if (environmental._statePattern.State == HouseState.Leaseed && environmental._statePattern.Time < 6)
            {
                Console.WriteLine($"{environmental._statePattern.Name}若是如今退房的話是不能退押金的!");
                environmental._statePattern.IsDeposit = false;
            }
            else
                Console.WriteLine($"{environmental._statePattern.Name}若是如今退房的話是能夠退押金的!");
            Console.WriteLine("考慮是否退房!");
        }
    }
}

 

namespace State_Pattern
{
    class Program
    {
        static void Main(string[] args)
        {
            //初始化房源信息
            List<StatePattern> statePatterns = new List<StatePattern>();
            statePatterns.Add(new StatePattern {Id=1,Name="房屋一",State=HouseState.Lease }); 

            Environmental environmental = new Environmental();
            //房屋一出租
            environmental.GetStatePattern(statePatterns.Where(x=>x.Id==1).FirstOrDefault());
            environmental.Show();

            //時間大於半年可退押金
            statePatterns[0].Time = 7;
            environmental.Show();


        }
    }
}

  在上面的代碼運行以後房屋一的狀態在其對象內部發送了改變,從而行爲也發送了變化。剛開始的正在出租改變成了簽定合同出租以後。行爲變化也從簽定合同轉變成了退房操做。 blog

使用場景及優缺點

1、使用場景

一、行爲隨着狀態改變而改變的場景。接口

二、條件或分支語句的替代者。

2、優勢

一、封裝了狀態及行爲的轉換規則。

二、在編寫錢枚舉出可能的狀態,肯定狀態的種類。

三、方便狀態的增長。只須要改變狀態便可改變對象的行爲。擴展性好。

四、能夠多個環境一塊兒共享一個狀態對象,減小了對象個數。

3、缺點

一、狀態模式會增長系統類和對象的個數

二、對開閉原則不友好。增長狀態須要對那些負責狀態轉換的代碼進行修改。不然的話沒法轉換到最新的狀態。

三、狀態模式的結構和實現都比較複雜,使用不當容易形成代碼混亂及難理解。

總結

  狀態模式到這裏介紹完了,狀態模式模式注重的狀態在內部的改變自動改變其行爲。對象看起來好像改變了它的類同樣。抓住重點實現。第一個是狀態的變化。第二個是狀態變化引發的行爲變化。第三個是在狀態內部改變的。把狀態的轉換邏輯和狀態對象放在一塊兒。繼而替換一個龐大的語句條件。


     時間抓起來講是金子,抓不住就是流水。

  C#設計模式系列目錄

     歡迎你們掃描下方二維碼,和我一塊兒踏上設計模式的闖關之路吧!

  

相關文章
相關標籤/搜索