深入理解設計模式之:狀態模式(State Pattern)
一、什么是狀態模式?
狀態模式(State Pattern)是一種行為型設計模式。它允許一個對象在其內部狀態發生改變時,改變其行為(即表現出不同的行為)。狀態模式將與狀態相關的行為封裝到獨立的狀態類中,并通過狀態切換來改變對象的行為。
核心思想:
將狀態的切換和行為的變化解耦,使得狀態切換變得靈活,代碼結構清晰,易于擴展和維護。
二、狀態模式的應用場景
- 對象的行為依賴于它的狀態,并且在運行時根據狀態發生改變
- 代碼中包含大量與狀態相關的條件語句(如 if-else 或 switch-case)
- 狀態切換頻繁,且狀態行為復雜
常見例子:
- 工作流引擎(如訂單狀態:待支付、已支付、已發貨、已完成等)
- TCP 連接狀態(CLOSED、LISTEN、SYN_SENT、ESTABLISHED 等)
- 游戲角色狀態(待機、攻擊、防御、死亡等)
三、狀態模式的結構
- Context(環境類):持有當前狀態對象,負責狀態切換
- State(抽象狀態):定義所有具體狀態的公共接口
- ConcreteState(具體狀態):實現具體狀態對應的行為
四、UML 類圖
+----------------+ +---------------------+
| Context |<>----->| State |
+----------------+ +---------------------+
| state: State | | + handle() |
| + setState() | +---------------------+
| + request() | /_\
+----------------+ ||+------------------+------------------+| |+---------------------+ +---------------------+| ConcreteStateA | | ConcreteStateB |+---------------------+ +---------------------+| + handle() | | + handle() |+---------------------+ +---------------------+
五、Java 實現代碼示例
1. 抽象狀態接口
public interface State {void handle(Context context);
}
2. 具體狀態類
public class StateA implements State {@Overridepublic void handle(Context context) {System.out.println("當前狀態:A,切換到狀態B");context.setState(new StateB());}
}public class StateB implements State {@Overridepublic void handle(Context context) {System.out.println("當前狀態:B,切換到狀態A");context.setState(new StateA());}
}
3. 環境類
public class Context {private State state;public Context(State state) {this.state = state;}public void setState(State state) {this.state = state;}public void request() {state.handle(this);}
}
4. 客戶端調用
public class Main {public static void main(String[] args) {Context context = new Context(new StateA());context.request(); // 輸出:當前狀態:A,切換到狀態Bcontext.request(); // 輸出:當前狀態:B,切換到狀態Acontext.request(); // 輸出:當前狀態:A,切換到狀態B}
}
六、實際應用案例:訂單狀態流轉
以電商訂單為例,訂單有“待支付”、“已支付”、“已發貨”、“已完成”四種狀態,每種狀態下允許的操作不同。
1. 狀態接口
public interface OrderState {void next(OrderContext ctx);void prev(OrderContext ctx);String getStatus();
}
2. 具體狀態類
public class PendingState implements OrderState {public void next(OrderContext ctx) {ctx.setState(new PaidState());}public void prev(OrderContext ctx) {System.out.println("已是初始狀態,不能回退");}public String getStatus() {return "待支付";}
}public class PaidState implements OrderState {public void next(OrderContext ctx) {ctx.setState(new ShippedState());}public void prev(OrderContext ctx) {ctx.setState(new PendingState());}public String getStatus() {return "已支付";}
}public class ShippedState implements OrderState {public void next(OrderContext ctx) {ctx.setState(new CompletedState());}public void prev(OrderContext ctx) {ctx.setState(new PaidState());}public String getStatus() {return "已發貨";}
}public class CompletedState implements OrderState {public void next(OrderContext ctx) {System.out.println("訂單已完成,不能再前進");}public void prev(OrderContext ctx) {ctx.setState(new ShippedState());}public String getStatus() {return "已完成";}
}
3. 環境類
public class OrderContext {private OrderState state;public OrderContext() {state = new PendingState();}public void setState(OrderState state) {this.state = state;}public void next() {state.next(this);}public void prev() {state.prev(this);}public void printStatus() {System.out.println("當前訂單狀態:" + state.getStatus());}
}
4. 客戶端調用
public class Main {public static void main(String[] args) {OrderContext order = new OrderContext();order.printStatus(); // 待支付order.next();order.printStatus(); // 已支付order.next();order.printStatus(); // 已發貨order.next();order.printStatus(); // 已完成order.next(); // 訂單已完成,不能再前進order.prev();order.printStatus(); // 已發貨}
}
七、狀態模式的優缺點
優點:
- 狀態切換邏輯清晰,易于擴展和維護
- 避免大量 if-else 或 switch-case
- 狀態行為封裝,符合開閉原則
缺點:
- 狀態類數量可能增多
- 結構相對復雜
八、總結
狀態模式是處理對象狀態切換和行為變化的經典方案,廣泛應用于工作流、狀態機、游戲開發等場景。掌握狀態模式有助于編寫靈活、可擴展的代碼結構。
建議:
- 當對象行為依賴于狀態且狀態切換復雜時,優先考慮狀態模式
- 狀態模式與策略模式、命令模式等常結合使用
如需更多設計模式講解或源碼分析,歡迎留言交流!