一、狀態模式概述
狀態模式(State Pattern)是一種行為型設計模式,它允許對象在其內部狀態改變時改變其行為,使對象看起來像是修改了它的類。這種模式將特定狀態相關的行為局部化,并且將不同狀態的行為分割開來。
狀態模式的核心價值:
-
消除龐大的條件語句:替代對象行為中基于狀態的if-else或switch-case語句
-
狀態轉換顯式化:將狀態轉換邏輯組織在單一位置
-
符合開閉原則:新增狀態無需修改現有狀態類
二、狀態模式結構
經典UML類圖:
classDiagramclass Context {-State _state+Request()+State}interface IState {<<interface>>+Handle(Context context)}class ConcreteStateA {+Handle(Context context)}class ConcreteStateB {+Handle(Context context)}Context o--> IStateIState <|-- ConcreteStateAIState <|-- ConcreteStateB
結構組成:
-
Context(上下文):維護一個ConcreteState子類的實例
-
State(狀態接口):定義所有具體狀態的共同接口
-
ConcreteState(具體狀態):實現與上下文特定狀態相關的行為
三、C#實現示例:訂單狀態系統
基礎實現版本:
//?狀態接口
public?interface?IOrderState
{void?Process(Order?order);void?Ship(Order?order);void?Cancel(Order?order);
}//?具體狀態:新建狀態
public?class?NewOrderState?:?IOrderState
{public?void?Process(Order?order){Console.WriteLine("開始處理訂單...");order.SetState(new?ProcessingOrderState());}public?void?Ship(Order?order)?=>?Console.WriteLine("訂單尚未處理,不能發貨!");public?void?Cancel(Order?order){Console.WriteLine("取消新訂單");order.SetState(new?CancelledOrderState());}
}//?具體狀態:處理中狀態
public?class?ProcessingOrderState?:?IOrderState
{public?void?Process(Order?order)?=>?Console.WriteLine("訂單已在處理中");public?void?Ship(Order?order){Console.WriteLine("訂單已發貨");order.SetState(new?ShippedOrderState());}public?void?Cancel(Order?order){Console.WriteLine("取消處理中的訂單");order.SetState(new?CancelledOrderState());}
}//?上下文類
public?class?Order
{private?IOrderState?_state;public?Order(){_state?=?new?NewOrderState();}public?void?SetState(IOrderState?state)?=>?_state?=?state;public?void?Process()?=>?_state.Process(this);public?void?Ship()?=>?_state.Ship(this);public?void?Cancel()?=>?_state.Cancel(this);
}
使用示例:
var?order?=?new?Order();
order.Process();??//?開始處理訂單...
order.Ship();?????//?訂單已發貨
order.Cancel();????//?訂單已發貨,無法取消
四、高級實現技巧
1. 狀態轉換表驅動
//?使用字典管理狀態轉換規則
public?class?OrderStateMachine
{private?readonly?Dictionary<Type,?StateTransitions>?_transitions;public?OrderStateMachine(){_transitions?=?new?Dictionary<Type,?StateTransitions>{[typeof(NewOrderState)]?=?new?StateTransitions{{?OrderAction.Process,?typeof(ProcessingOrderState)?},{?OrderAction.Cancel,?typeof(CancelledOrderState)?}},//?其他狀態轉換規則...};}public?Type?GetNextState(Type?current,?OrderAction?action)=>?_transitions[current][action];
}
2. 結合依賴注入
//?在Startup.cs中注冊狀態
services.AddTransient<NewOrderState>();
services.AddTransient<ProcessingOrderState>();
//?其他狀態...//?修改上下文類使用DI
public?class?Order
{private?IOrderState?_state;private?readonly?IServiceProvider?_services;public?Order(IServiceProvider?services){_services?=?services;_state?=?_services.GetRequiredService<NewOrderState>();}public?void?SetState<T>()?where?T?:?IOrderState?=>?_state?=?_services.GetRequiredService<T>();
}
五、狀態模式最佳實踐
1. 何時使用狀態模式:
-
對象的行為取決于它的狀態,并且必須在運行時根據狀態改變行為
-
操作中包含大量與對象狀態相關的條件語句
-
當狀態數量超過5個且可能繼續增加時
2. 性能優化策略:
-
狀態對象復用:無狀態的狀態對象可以設計為單例
-
緩存狀態轉換:預計算并緩存可能的轉換路徑
-
異步狀態處理:對耗時操作實現異步狀態處理
//?異步狀態接口
public?interface?IAsyncOrderState
{Task?ProcessAsync(Order?order);Task?ShipAsync(Order?order);Task?CancelAsync(Order?order);
}
3. 與其它模式的結合:
-
策略模式:狀態模式可以視為策略模式的擴展,但策略模式不處理狀態轉換
-
觀察者模式:在狀態變更時通知相關觀察者
-
備忘錄模式:實現狀態歷史回溯
六、實際應用案例
電商訂單系統狀態圖:
stateDiagram-v2[*] --> NewNew --> Processing: 處理訂單Processing --> Shipped: 發貨Processing --> Cancelled: 取消Shipped --> Delivered: 送達Shipped --> Returned: 退貨Delivered --> Returned: 退貨Cancelled --> [*]Returned --> [*]
游戲角色狀態實現:
public?class?Player
{private?IPlayerState?_state;public?void?Attack()?=>?_state.Attack(this);public?void?Move()?=>?_state.Move(this);//?狀態切換方法public?void?TakeDamage()?=>?SetState(new?HurtState());public?void?Heal()?=>?SetState(new?NormalState());
}public?interface?IPlayerState
{void?Attack(Player?player);void?Move(Player?player);
}public?class?NormalState?:?IPlayerState
{public?void?Attack(Player?player)?=>?Console.WriteLine("造成100%傷害");public?void?Move(Player?player)?=>?Console.WriteLine("100%移動速度");
}public?class?HurtState?:?IPlayerState
{public?void?Attack(Player?player)?=>?Console.WriteLine("造成70%傷害");public?void?Move(Player?player)?=>?Console.WriteLine("80%移動速度");
}
七、狀態模式優缺點分析
優點:
-
單一職責原則:將與特定狀態相關的代碼放在獨立的類中
-
開閉原則:無需修改已有狀態類和上下文就能引入新狀態
-
消除龐大的條件分支語句
缺點:
-
可能過度設計:如果狀態很少或很少改變,會增加不必要的復雜性
-
狀態對象間可能產生耦合:狀態轉換需要了解其他狀態
-
性能開銷:頻繁創建狀態對象可能帶來開銷(可通過對象池優化)
八、總結
狀態模式是處理復雜狀態邏輯的強大工具,在C#中通過接口和具體類的組合可以優雅地實現。在實際開發中,建議:
-
對狀態超過3個且可能增長的系統優先考慮
-
結合DI容器管理狀態對象生命周期
-
對復雜狀態轉換使用狀態機模式增強
-
考慮使用狀態模式庫(如Stateless)處理復雜場景
通過合理應用狀態模式,可以使代碼更易維護、擴展性更強,特別是在業務規則頻繁變化的領域(如訂單系統、游戲開發、工作流引擎等)能顯著提升代碼質量。