設計模式20之狀態模式

Lvshen的技術小屋發表於2020-11-23

背景

在開發過程中,物件會有根據不同的情況做出不同的行為,而影響行為的屬性稱之為狀態屬性,這個物件也就是狀態物件。

我們在編碼時,可能會使用if-else來做狀態判斷。例如我有一個活動類Activity,這個類裡面有一個活動開始欄位,活動結束欄位,還有一個狀態欄位,現在我們要來判斷活動的狀態:未開始、進行中、已結束。示例程式碼如下:

當狀態很多,那麼程式會變得很複雜。如果有新的狀態增加,就要新增新的if語句,違背設計原則中的開閉原則。

所以我們採用狀態模式來解決這個問題,我們將物件狀態的判斷邏輯抽離出來,放到一個狀態類中,這樣將原本複雜的邏輯判斷簡單化。

什麼是狀態模式

Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(當一個物件內在狀態改變時允許其改變行為,這個物件看起來像改變了其類。)

狀態模式由下面3個要素構成:

  • 環境(Context)角色:也稱為上下文,它定義了客戶感興趣的介面,維護一個當前狀態,並將與狀態相關的操作委託給當前狀態物件來處理。

  • 抽象狀態(State)角色:定義一個介面,用以封裝環境物件中的特定狀態所對應的行為。

  • 具體狀態(Concrete  State)角色:實現抽象狀態所對應的行為。

結構圖如下:

狀態模式

示例程式碼

State

public abstract class State {
    public abstract void handle(Context context);
}

Context

public class Context {
    private State state;

    //定義環境類的初始狀態
    public Context() {
        this.state = new ConcreteStateA();
    }

    //設定新狀態
    public void setState(State state) {
        this.state = state;
    }

    //讀取狀態
    public State getState() {
        return (state);
    }

    //對請求做處理
    public void handle() {
        state.handle(this);
    }
}

ConcreteState

public class ConcreteStateA extends State{
    public void handle(Context context)
    {
        System.out.println("當前狀態是 A.");
        context.setState(new ConcreteStateB());
    }
}

public class ConcreteStateB extends State{
    public void handle(Context context)
    {
        System.out.println("當前狀態是 B.");
        context.setState(new ConcreteStateA());
    }
}

測試程式碼

@Test
public void test() {
    Context context=new Context();    //建立環境
    context.handle();    //處理請求
    context.handle();
    context.handle();
    context.handle();
}

測試結果:

當前狀態是 A.
當前狀態是 B.
當前狀態是 A.
當前狀態是 B.

我們每呼叫一次handle(),就改變一次狀態。

關於狀態模式的思考

經過上面的講解,你肯定知道狀態模式的使用場景了吧。當物件的行為取決於它的狀態,並且在執行時會根據他的狀態來改變它的行為。我們就可以考慮使用狀態模式。

狀態模式的好處在於,我可以避免寫過多的switch-case或者if-else語句。這樣避免了程式的過分複雜。

從上面的程式碼我們可以知道,開發者無需知道狀態的改變細節。這種良好的封裝性是我們的程式碼更優雅。

但是你是否意識到,如果狀態型別太多,那麼就要寫很多的狀態子類,這樣也會加大系統的管理難度。使用狀態模式的時候要考慮這方面的問題。

關於消除if-else,我之前也寫過文章使用列舉和策略模式消除,現在又多了一種方法?。感興趣的可以看看我之前寫的文章:

?如何用列舉消除if/else?-列舉高階用法

?公司系統if-else語句太多了,我用設計模式消除了if-else

這篇文章就寫到這裡啦,謝謝閱讀!

往期推薦

掃碼二維碼,獲取更多精彩。或微信搜Lvshen_9,可後臺回覆獲取資料

  1. 回覆"java" 獲取java電子書;

  2. 回覆"python"獲取python電子書;

  3. 回覆"演算法"獲取演算法電子書;

  4. 回覆"大資料"獲取大資料電子書;

  5. 回覆"spring"獲取SpringBoot的學習視訊。

  6. 回覆"面試"獲取一線大廠面試資料

  7. 回覆"進階之路"獲取Java進階之路的思維導圖

  8. 回覆"手冊"獲取阿里巴巴Java開發手冊(嵩山終極版)

  9. 回覆"總結"獲取Java後端面試經驗總結PDF版

  10. 回覆"Redis"獲取Redis命令手冊,和Redis專項面試習題(PDF)

  11. 回覆"併發導圖"獲取Java併發程式設計思維導圖(xmind終極版)

另:點選【我的福利】有更多驚喜哦。

相關文章