軟體設計模式系列之二十二——狀態模式

cooldream2009發表於2023-10-04

1 模式的定義

狀態模式是一種行為型設計模式,它允許物件在內部狀態發生改變時改變其行為,使得物件的行為看起來像是改變了其類。狀態模式將物件的狀態抽象成一個獨立的類,讓物件在不同狀態下具有不同的行為,而且可以在執行時切換狀態。這種方式使得狀態的管理更加清晰,避免了大量的條件判斷語句,提高了程式碼的可維護性和可擴充套件性。

2 舉例說明

在日常生活中,有許多符合狀態模式併為大家所熟知的例子。以下是幾個常見的例子:

交通訊號燈。
交通訊號燈是一個典型的狀態模式的例子。它有三種狀態:紅燈、綠燈和黃燈。每種狀態都對應著不同的行為,如紅燈停、綠燈行、黃燈準備停等。訊號燈在不同狀態之間切換,根據交通需求控制交通流量。

遊戲角色狀態。
在電子遊戲中,遊戲角色通常有多種狀態,如站立、行走、奔跑、攻擊等。玩家透過控制輸入來改變遊戲角色的狀態,從而實現不同的行為。

自動售貨機。
自動售貨機也是一個狀態模式的例子。它通常有多個狀態,如空閒、接受貨幣、選擇商品、出貨等。售貨機會根據使用者的操作和投入的貨幣來改變狀態,最終完成購買過程。

這些例子都展示了狀態模式在日常生活中的廣泛應用。它們透過將物件的狀態抽象成不同的類,並根據當前狀態執行相應的行為,實現了狀態和行為的解耦,提高了系統的靈活性和可維護性。

3 結構

狀態模式的主要結構包括以下幾個角色:

Context(上下文):維護一個對具體狀態物件的引用,負責將客戶端的請求委派給當前狀態物件處理。

State(狀態抽象類或介面):定義一個介面或抽象類,用於封裝與Context相關的一個或多個行為。

ConcreteState(具體狀態類):實現State介面或繼承State抽象類,具體實現狀態相關的行為。

Client(客戶端):使用Context來與狀態物件進行互動,不直接與具體狀態類互動。

4 實現步驟

實現狀態模式的關鍵步驟如下:

定義狀態抽象類或介面(State),宣告狀態相關的方法。

建立具體狀態類,實現狀態抽象類或介面中的方法,每個具體狀態類代表一個狀態。

建立上下文類(Context),維護一個對當前狀態物件的引用,並將請求委派給當前狀態物件處理。

在客戶端中建立上下文物件,透過上下文物件來與狀態物件互動。

5 程式碼實現(Java)

下面是一個簡單的狀態模式的Java示例,實現一個電梯控制系統:

// 步驟1: 定義狀態抽象類
interface State {
    void open();
    void close();
    void run();
    void stop();
}

// 步驟2: 建立具體狀態類
class OpenState implements State {
    // 實現狀態相關的方法
    // ...
}

class CloseState implements State {
    // 實現狀態相關的方法
    // ...
}

class RunState implements State {
    // 實現狀態相關的方法
    // ...
}

class StopState implements State {
    // 實現狀態相關的方法
    // ...
}

// 步驟3: 建立上下文類
class Context {
    private State currentState;

    public void setState(State state) {
        this.currentState = state;
    }

    public void request() {
        currentState.handle();
    }
}

// 步驟4: 在客戶端中使用狀態模式
public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setState(new CloseState());

        // 在不同狀態下請求
        context.request();
    }
}

6 典型應用場景

狀態模式適用於以下情況:

物件的行為隨著其內部狀態的改變而改變:如果一個物件有多個狀態,且在不同狀態下需要不同的行為,狀態模式是一個合適的選擇。它允許物件在執行時根據其狀態切換行為,而無需大量的條件判斷語句。

條件語句過多且難以維護:當一個物件有多個狀態,並且在不同狀態下需要執行不同的操作時,通常會導致大量的條件語句。狀態模式能夠將這些條件邏輯封裝在不同的狀態類中,使得程式碼更加清晰、可維護,並降低錯誤的風險。

狀態轉換需要動態性:如果狀態之間的轉換規則需要在執行時動態改變,狀態模式可以靈活應對這種需求。狀態模式使得狀態切換變得容易,可以根據特定條件自動切換狀態。

物件的狀態會頻繁變化:如果物件的狀態會頻繁發生改變,使用狀態模式可以簡化狀態管理,並且使得狀態變化對系統的影響更加可控。

需要避免使用大量條件判斷語句:狀態模式能夠避免大量的條件判斷語句,提高程式碼的可讀性和可維護性。這對於複雜的狀態管理場景特別有用。

物件的行為和狀態無法簡單對映為列舉型別:有時物件的狀態和行為並不容易用簡單的列舉型別表示,而是需要更多的靈活性和複雜性。狀態模式可以提供這種靈活性。

希望透過組合而不是繼承來擴充套件物件的行為:狀態模式是一種物件組合的方式,可以透過組合不同的狀態類來擴充套件物件的行為,而不是透過繼承來實現。

總之,狀態模式在處理物件的狀態和行為之間的複雜關係,以及需要將狀態轉換邏輯封裝、分離和可維護時,是一個非常有用的設計模式。它能夠提高程式碼的可擴充套件性、可讀性和可維護性,尤其在需要處理多個狀態和狀態之間複雜轉換規則的情況下表現出色。

7 優缺點

優點:

將狀態相關的行為封裝到不同的狀態類中,提高了程式碼的可維護性和可讀性。
可以輕鬆新增新的狀態類,擴充套件系統的行為。
避免了大量的條件判斷語句,使得程式碼更加簡潔。

缺點:

如果狀態轉換邏輯過於複雜,可能會導致類的數量增加,增加維護難度。
不適用於所有情況,只有當物件的行為與其狀態密切相關時才適用。

8 類似模式

策略模式(Strategy Pattern):

策略模式和狀態模式都允許物件在執行時改變其行為,但它們的目的不同。狀態模式關注物件在不同狀態下的行為變化,而策略模式關注在相同狀態下不同演算法的選擇。在策略模式中,演算法可以隨時替換,而在狀態模式中,狀態會影響物件的行為。電梯控制系統可以使用狀態模式來管理電梯狀態(停止、上升、下降),而支付系統可以使用策略模式來選擇不同的支付策略(信用卡支付、支付寶支付)。

責任鏈模式(Chain of Responsibility Pattern):

責任鏈模式和狀態模式都可以透過物件之間的協作來處理請求,但它們的目的和結構不同。責任鏈模式用於處理多個處理器物件,每個處理器可以選擇處理請求、傳遞給下一個處理器或者中斷鏈條。狀態模式用於物件狀態的管理,每個狀態物件負責處理物件在特定狀態下的請求。請假申請審批系統可以使用責任鏈模式,不同級別的審批者可以構成責任鏈,每個審批者可以選擇批准、拒絕或者將請求傳遞給下一個審批者。在狀態模式中,審批狀態可以是一種狀態。

雖然這些模式有相似之處,但它們在解決不同問題和場景中具有不同的應用。選擇合適的模式取決於問題的性質和需求。

9 小結

狀態模式是一種強大的設計模式,用於管理物件的狀態和行為,使得系統更加靈活和可擴充套件。透過將狀態抽象成獨立的類,狀態模式消除了大量的條件判斷,使得程式碼更加清晰易懂。在實際應用中,狀態模式可以幫助我們構建更加可維護和可擴充套件的系統,提高程式碼質量和可讀性。無論是電梯控制系統還是訂單狀態管理,狀態模式都可以發揮其優勢,讓軟體設計更加優雅和靈活。希望本文能夠幫助讀者深入理解狀態模式,並在實際專案中靈活運用。

相關文章