首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 狀態模式 (State Pattern) 實戰:以傳送帶門控制為例

     編輯:Java 相關知識

何時需要狀態模式?

當物件的行為隨內部狀態劇烈改變,且狀態轉換邏輯散落在大量 if/else 或 switch 中時,狀態模式能將「每種狀態的行為」封裝為獨立類別,透過多型分派,消除條件判斷,符合開放封閉原則。

案例:傳送帶門狀態機

需求:單一按鈕控制門,初始關閉。按一下 → 開啟中;開啟中再按 → 關閉中;完全開啟後 2 秒自動關閉;開啟狀態下按一下 → 保持開啟 (禁止自動關閉)。

UML 狀態機圖

傳統實作 (未使用模式)

public class Door1 extends Observable {
    public static final int CLOSED = 1, OPENING = 2, OPEN = 3, CLOSING = 4, STAYOPEN = 5;
    private int state = CLOSED;

    public void click() {
        if (state == CLOSED) setState(OPENING);
        else if (state == OPENING || state == STAYOPEN) setState(CLOSING);
        else if (state == OPEN) setState(STAYOPEN);
        else if (state == CLOSING) setState(OPENING);
    }

    private void setState(int state) {
        this.state = state;
        setChanged(); notifyObservers();
    }
    // ... status() 等輔助方法
}

缺點:狀態邏輯集中在 click(),新增狀態需修改此方法,違反 OCP;若有多個事件 (如 timeout、sensor) 需處理,if/else 會指數級膨脹。

狀態模式重構

1. 狀態介面

public interface DoorState {
    void click(DoorContext ctx);
    void timeout(DoorContext ctx);
    void sensor(DoorContext ctx);
    String getName();
}

2. 具體狀態類別

public class ClosedState implements DoorState {
    public void click(DoorContext ctx) { ctx.setState(new OpeningState()); }
    public void timeout(DoorContext ctx) {}
    public void sensor(DoorContext ctx) {}
    public String getName() { return "CLOSED"; }
}

public class OpeningState implements DoorState {
    public void click(DoorContext ctx) { ctx.setState(new ClosingState()); }
    public void timeout(DoorContext ctx) {} // 由硬體觸發完全開啟事件
    public void sensor(DoorContext ctx) { ctx.setState(new OpenState()); } // 門已全開
    public String getName() { return "OPENING"; }
}

// OpenState, ClosingState, StayOpenState 同理...

3. Context 委派者

public class DoorContext extends Observable {
    private DoorState state = new ClosedState();

    public void setState(DoorState newState) {
        this.state = newState;
        setChanged(); notifyObservers();
    }

    public void click() { state.click(this); }
    public void timeout() { state.timeout(this); }
    public void sensor() { state.sensor(this); }
    public String status() { return state.getName(); }
}

優勢對比

維度傳統 if/else狀態模式
新增狀態修改核心邏輯類新增 State 實作類,零修改既有碼
程式碼分散度集中在幾個巨大方法分散於各 State 類,單一職責
測試性需構建複雜前置條件可單獨測試每個 State 行為
執行效能多條件判斷單一虛擬方法分派,極快

應用場景

  • 訂單流程 (新建 → 付款 → 出貨 → 完成/取消)
  • 遊戲角色狀態 (待機、移動、攻擊、死亡)
  • 工作流引擎、通訊協定狀態機 (TCP、HTTP/2)
  • UI 元件 (按鈕:正常、懸停、按下、停用)

注意事項

  • 狀態類數量過多時,可考慮狀態表驅動 (State Table) 或層狀狀態機 (Hierarchical State Machine)
  • 狀態轉換動作若需共享邏輯,可抽取基底類或使用策略模式組合
  • Java enum 實作狀態模式 (每個 enum 常數實作介面) 是輕量替代方案
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved