[Design Pattern] 狀態模式(State Pattern)

[Design Pattern] 狀態模式(State Pattern)

State Pattern 主要是解決控制一個物件狀態條件表達過於複雜的情況(簡化複雜的判斷邏輯)。

我們常看到很多流程判斷幾乎都使用一連串 if else..或 switch 來判斷某個狀態後得到什麼結果,

雖然一開始需求很少判斷條件寫起來也很少,當然 if else 自然也就沒啥問題,

但需求變動在這行是不可避免的,後續只要需求有異動,

大部分的開發人員會很直覺的添加if else或 switch 條件,

以至於最後整個程式碼變的相當攏長也相當難維護,

而 State Pattern 將每個條件分支抽取成獨立類別,

每一個狀態都視成一個獨立物件(減少物件彼此依賴),

這樣往後需求有變更時,大多也不用有太大的變更,

但由於把每個條件分支抽取成獨立類別,所以無法去避免類別變多的情況發生。

 

 

UML

image

 

需求:假設有個工單流程,User提出工單給負責人員,

然後負責人員回報處理狀況,User 確認後結束該工單。

 

複雜的判斷邏輯

private static string GetState()
        {
            string result = string.Empty;

	
            if (WorkOrderState == "申請")
            {
                result = "工作單申請";
                WorkOrderState = "負責人";
            }
            else if (WorkOrderState == "負責人")
            {
                result = "負責人處理中";
                WorkOrderState = "使用者";
            }
            else if (WorkOrderState == "使用者")
            {
                result = "使用者確認中";
                WorkOrderState = "結束";
            }
            else if (WorkOrderState == "結束")
            {
                result = "該單結案";            
            }

	
            return result;
        }

 

 

 

 

 

 

Client

 static string WorkOrderState = "申請"; 
        static void Main(string[] args)
        {

	
            Console.WriteLine("工作單現在狀態:{0}", GetState());
            Console.WriteLine("工作單現在狀態:{0}", GetState());
            Console.WriteLine("工作單現在狀態:{0}", GetState());
            Console.WriteLine("工作單現在狀態:{0}", GetState());          

	
            Console.ReadLine();
        }

 

 

 

 

 

 

 

 

 

 

 

image

 

簡化複雜邏輯

新增 Content 類別定義當前狀態類別

class Context
    {
        private State _state;
        public State State
        {
            get { return this._state; }
            set { this._state = value; }
        }

	
        private string _action;
        public string Action
        {
            get { return this._action; }
            set { this._action = value; }
        }

	
        public Context()
        {
            this._state = new StartState();
            this._action = "申請";//初始狀態
        }

	
        public string GetState()
        {
           return _state.GetState(this);
        }
    }

 

 

 

 

 

 

新增抽象狀態類別(State)並定義一個抽象方法GetState(),

同時將每個條件獨立成個別類別,並繼承抽象類別(State)。

//抽象狀態類別
    abstract class State
    {
        public abstract string GetState(Context context);
    }

	
    //開始狀態類別
    class StartState : State
    {
        public override string GetState(Context context)
        {
            if (context.Action == "申請")
            {
                context.Action = "負責人";
                return "工作單申請";
            }               
            else
            {
                context.State =new OwnerState();
                return context.GetState();              
            }
        }
    }

	
    //負責人狀態類別
    class OwnerState : State
    {
        public override string GetState(Context context)
        {
            if (context.Action == "負責人")
            {
                context.Action = "使用者";
                return "負責人處理中";
            }                
            else
            {
                context.State =new UserState();
                return context.GetState();              
            }
        }
    }

	
    //使用者狀態類別
    class UserState : State
    {
        public override string GetState(Context context)
        {
            if (context.Action == "使用者")
            {
                context.Action = "結束";
                return "使用者確認中";
            }              
            else
            {
                context.State =new FinallyState();
                return context.GetState();               
            }
        }
    }

	
    //結案類別
    class FinallyState : State
    {
        public override string GetState(Context context)
        {
            if (context.Action == "結束")
            {
                return "該單結案";
            }               
       }
    }

 

 

 

 

 

 

 

 

Client

 static void Main(string[] args)
        {       
            Context context = new Context();
            Console.WriteLine("工作單現在狀態:{0}", context.GetState());
            Console.WriteLine("工作單現在狀態:{0}", context.GetState());
            Console.WriteLine("工作單現在狀態:{0}", context.GetState());
            Console.WriteLine("工作單現在狀態:{0}", context.GetState());

	
            Console.ReadLine();
        }

 

 

 

 

 

image 

 

往後如果需求有所變動,好比負責人不在時要有代理人來處理問題,

這時你只需要新增代理人類別並修改一下負責人狀態類別就可以很輕鬆完成該需求,

而且也不影響其他狀態的邏輯狀態判斷。 

 

 

參考

State pattern

大話設計模式