狀態模式詳解
一、狀態模式概述
狀態模式(State Pattern)是一種行為型設計模式,它允許一個對象在其內部狀態改變時改變它的行為,使對象看起來似乎修改了它的類。
核心特點
- 狀態封裝:將每個狀態的行為封裝到獨立的類中
- 狀態轉換:對象在不同狀態間透明切換
- 消除條件判斷:用多態代替狀態條件判斷
- 開閉原則:新增狀態無需修改現有代碼
二、狀態模式的結構
主要角色
- Context:上下文,維護當前狀態
- State:抽象狀態,定義狀態接口
- ConcreteState:具體狀態,實現特定狀態行為
三、狀態模式的實現
1. 基本實現
// 狀態接口
public interface State {void handle(Context context);
}// 具體狀態A
public class ConcreteStateA implements State {public void handle(Context context) {System.out.println("處理狀態A的行為");context.setState(new ConcreteStateB());}
}// 具體狀態B
public class ConcreteStateB implements State {public void handle(Context context) {System.out.println("處理狀態B的行為");context.setState(new ConcreteStateA());}
}// 上下文類
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);}
}// 使用示例
Context context = new Context(new ConcreteStateA());
context.request(); // 執行狀態A的行為,并切換到狀態B
context.request(); // 執行狀態B的行為,并切換回狀態A
2. 更復雜的實現(訂單狀態)
// 訂單狀態接口
public interface OrderState {void next(Order order);void prev(Order order);void printStatus();
}// 新建狀態
public class NewState implements OrderState {public void next(Order order) {order.setState(new PaidState());}public void prev(Order order) {System.out.println("訂單已在初始狀態");}public void printStatus() {System.out.println("訂單狀態:新建");}
}// 已支付狀態
public class PaidState implements OrderState {public void next(Order order) {order.setState(new ShippedState());}public void prev(Order order) {order.setState(new NewState());}public void printStatus() {System.out.println("訂單狀態:已支付");}
}// 訂單類(上下文)
public class Order {private OrderState state;public Order() {this.state = new NewState();}public void setState(OrderState state) {this.state = state;}public void nextState() {state.next(this);}public void previousState() {state.prev(this);}public void printStatus() {state.printStatus();}
}
四、狀態模式的應用場景
1. 電梯狀態控制
// 電梯狀態接口
public interface ElevatorState {void openDoor();void closeDoor();void run();void stop();
}// 運行狀態
public class RunningState implements ElevatorState {public void openDoor() {System.out.println("電梯運行中不能開門");}public void closeDoor() {System.out.println("電梯門已是關閉狀態");}public void run() {System.out.println("電梯已在運行");}public void stop() {System.out.println("電梯停止運行");}
}// 停止狀態
public class StoppedState implements ElevatorState {public void openDoor() {System.out.println("電梯門打開");}public void closeDoor() {System.out.println("電梯門關閉");}public void run() {System.out.println("電梯開始運行");}public void stop() {System.out.println("電梯已是停止狀態");}
}
2. 游戲角色狀態
// 游戲角色狀態
public interface CharacterState {void attack();void defend();void move();
}// 正常狀態
public class NormalState implements CharacterState {public void attack() {System.out.println("造成100%傷害");}public void defend() {System.out.println("受到100%傷害");}public void move() {System.out.println("移動速度100%");}
}// 中毒狀態
public class PoisonedState implements CharacterState {public void attack() {System.out.println("造成80%傷害");}public void defend() {System.out.println("受到120%傷害");}public void move() {System.out.println("移動速度60%");}
}
3. TCP連接狀態
// TCP狀態接口
public interface TCPState {void open();void close();void acknowledge();
}// 已建立連接狀態
public class EstablishedState implements TCPState {public void open() {System.out.println("連接已建立,無需再次打開");}public void close() {System.out.println("關閉TCP連接");}public void acknowledge() {System.out.println("發送ACK響應");}
}// 監聽狀態
public class ListenState implements TCPState {public void open() {System.out.println("建立TCP連接");}public void close() {System.out.println("未建立連接,無需關閉");}public void acknowledge() {System.out.println("未建立連接,不能發送ACK");}
}
五、狀態模式的變體
1. 狀態表驅動
public class StateMachine {private Map<State, Map<Event, State>> transitions = new HashMap<>();private State currentState;public void addTransition(State source, Event event, State target) {transitions.computeIfAbsent(source, k -> new HashMap<>()).put(event, target);}public void handleEvent(Event event) {currentState = transitions.get(currentState).get(event);}
}
2. 狀態模式與策略模式結合
public class Context {private StateStrategy state;public void setState(StateStrategy state) {this.state = state;}public void execute() {state.execute();state = state.nextState();}
}public interface StateStrategy {void execute();StateStrategy nextState();
}
六、狀態模式的優缺點
優點
- 單一職責:每個狀態一個類
- 開閉原則:易于新增狀態
- 簡化上下文:消除大量條件判斷
- 狀態轉換顯式:狀態轉換邏輯清晰
缺點
- 類數量多:狀態多時代碼量大
- 過度設計:簡單狀態機可能不適用
- 狀態共享:狀態間共享數據較復雜
七、最佳實踐
- 合理劃分狀態:避免狀態粒度過細
- 共享狀態對象:無狀態的狀態對象可共享
- 狀態轉換控制:集中或分散管理轉換邏輯
- 結合其他模式:如與策略模式結合
- 文檔化狀態圖:維護狀態轉換關系圖
八、總結
狀態模式是管理對象狀態的有效方案,特別適用于:
- 對象行為隨狀態改變而改變
- 需要消除大量狀態條件判斷
- 狀態轉換邏輯復雜
- 需要清晰的狀態管理
在實際開發中,狀態模式常見于:
- 工作流引擎
- 游戲角色狀態
- 設備控制(如電梯、自動售貨機)
- 網絡協議實現
- 訂單生命周期管理
正確使用狀態模式可以創建清晰、可維護的狀態管理代碼,但需要注意避免過度設計簡單場景。