前言
今天我們講的是狀態模式【State Pattern】、這個名字咋一看不好理解,但是仔細一想還是比較容易的,狀態模式重點關注的是狀態,狀態又牽扯著什么呢?房屋的狀態暫且可以分為出租、簽訂合同、退房,那么出租對應的是什么呢?出租狀態代表可以租房,可以租房是一個行為了,所以不難理解的是狀態模式關注的是狀態的改變與行為的變化,
狀態模式介紹
一、來由
在軟體系統中,經常狀態的改變影響著行為的變化,例如房屋狀態是出租既可以租房、出售既可以買賣房、不租售意味不可操作,那么如何避免物件操作和狀態轉換之間出現緊耦合呢?狀態模式將每種狀態對應的行為抽象出來成為單獨新的物件,這樣狀態的變化不再依賴于物件內部的行為正解決了此問題,
二、意圖
允許物件在內部狀態發生改變時改變它的行為,物件看起來好像修改了它的類,
三、案例圖

四、狀態模式代碼示例
我們看下案例圖中主要三個部分:
環境角色:包含保留了一個具體狀態的實體、給出當前狀態及呼叫方法,
抽象狀態:定義介面、封裝一個狀態相對應的行為方法,
具體狀態:實作具體狀態對應的的具體對應行為,
我們繼續看這個房屋的案例,針對房屋我們整理這么一個案例,租房然后簽訂合同,合同半年內退房無押金,租房時間達到半年退房可得押金,我們看下代碼實作吧:
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(); } }}
在上面的代碼運行之后房屋一的狀態在其物件內部發送了改變,從而行為也發送了變化,剛開始的正在出租改變成了簽訂合同出租之后,行為變化也從簽訂合同轉變成了退房操作,

使用場景及優缺點
一、使用場景
1、行為隨著狀態改變而改變的場景,
2、條件或分支陳述句的替代者,
二、優點
1、封裝了狀態及行為的轉換規則,
2、在撰寫錢列舉出可能的狀態,確定狀態的種類,
3、方便狀態的增加,只需要改變狀態即可改變物件的行為,擴展性好,
4、可以多個環境一起共享一個狀態物件,減少了物件個數,
三、缺點
1、狀態模式會增加系統類和物件的個數
2、對開閉原則不友好,增加狀態需要對那些負責狀態轉換的代碼進行修改,否則的話無法轉換到最新的狀態,
3、狀態模式的結構和實作都比較復雜,使用不當容易造成代碼混亂及難理解,
總結
狀態模式到這里介紹完了,狀態模式模式注重的狀態在內部的改變自動改變其行為,物件看起來好像改變了它的類一樣,抓住重點實作,第一個是狀態的變化,第二個是狀態變化引起的行為變化,第三個是在狀態內部改變的,把狀態的轉換邏輯和狀態物件放在一起,繼而替換一個龐大的陳述句條件,
時間抓起來說是金子,抓不住就是流水,
C#設計模式系列目錄
歡迎大家掃描下方二維碼,和我一起踏上設計模式的闖關之路吧!

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/39952.html
標籤:設計模式
上一篇:組合模式
下一篇:設計模式之?代理模式
