1. 程式人生 > >java設計模式---狀態模式(State pattern)

java設計模式---狀態模式(State pattern)

java設計模式—狀態模式(State pattern)

1. 概述
狀態模式用於解決系統中複雜物件的狀態轉換以及不同狀態下行為的封裝問題。當系統中某個物件存在多個狀態,這些狀態之間可以進行轉換,而且物件在不同狀態下行為不相同時可以使用狀態模式。狀態模式將一個物件的狀態從該物件中分離出來,封裝到專門的狀態類中,使得物件狀態可以靈活變化,對於客戶端而言,無須關心物件狀態的轉換以及物件所處的當前狀態,無論對於何種狀態的物件,客戶端都可以一致處理。
2. 定義
狀態模式(State Pattern):允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類。其別名為狀態物件(Objects for States),狀態模式是一種物件行為型模式。
3. UML圖


這裡寫圖片描述
從上圖我們可以看到在狀態模式中包含如下幾個角色:
Context(環境類):環境類又稱為上下文類,它是擁有多種狀態的物件。由於環境類的狀態存在多樣性且在不同狀態下物件的行為有所不同,因此將狀態獨立出去形成單獨的狀態類。在環境類中維護一個抽象狀態類 State 的例項,這個例項定義當前狀態,在具體實現時,它是一個 State 子類的物件。
State(抽象狀態類):它用於定義一個介面以封裝與環境類的一個特定狀態相關的行為,在抽象狀態類中聲明瞭各種不同狀態對應的方法,而在其子類中實現類這些方法,由於不同狀態下物件的行為可能不同,因此在不同子類中方法的實現可能存在不同,相同的方法可以寫在抽象狀態類中。
ConcreteState(具體狀態類)
:它是抽象狀態類的子類,每一個子類實現一個與環境類的一個狀態相關的行為,每一個具體狀態類對應環境的一個具體狀態,不同的具體狀態類其行為有所不同。
4. 簡單實現

//定義抽象的狀態介面
public interface State {
    void handle();
}
//定義環境類
public class Context {
    private State state;

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

    public void request()
    {
        state.handle();
    }
}
//定義具體的狀態
public class ConcreateStateA implements State { @Override public void handle() { //TODO: 具體的狀態A的業務邏輯 } }

5. 簡單示例
我們就以簡單的使用者登入系統為例,程式碼實現如下:

//定義抽象的狀態(此處為action)
public interface Action {
    void doAction();
}
//定義兩個具體的狀態
public class LoginAction implements Action {
    @Override
    public void doAction() {
        //TODO:執行登入後的業務
    }
}
public class LogoutAction implements Action {
    @Override
    public void doAction() {
        //TODO:執行退出後的業務
    }
}
//定義具體的環境類
public class UserContext {
    private Action action;

    public void setAction(Action action) {
        this.action = action;
    }

    public void request()
    {
        action.doAction();
    }
}

6. 優缺點
6.1 優點
(1) 封裝了狀態的轉換規則,在狀態模式中可以將狀態的轉換程式碼封裝在環境類或者具體狀態類中,可以對狀態轉換程式碼進行集中管理,而不是分散在一個個業務方法中。
(2) 將所有與某個狀態有關的行為放到一個類中,只需要注入一個不同的狀態物件即可使環境物件擁有不同的行為。
(3) 允許狀態轉換邏輯與狀態物件合成一體,而不是提供一個巨大的條件語句塊,狀態模式可以讓我們避免使用龐大的條件語句來將業務方法和狀態轉換程式碼交織在一起。
(4) 可以讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數。
6.2 缺點
(1) 狀態模式的使用必然會增加系統中類和物件的個數,導致系統執行開銷增大。
(2) 狀態模式的結構與實現都較為複雜,如果使用不當將導致程式結構和程式碼的混亂,增加系統設計的難度。
(3) 狀態模式對“開閉原則”的支援並不太好,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法轉換到新增狀態;而且修改某個狀態類的行為也需修改對應類的原始碼。
7. 使用場景
在以下情況下可以考慮使用狀態模式:
(1) 物件的行為依賴於它的狀態(如某些屬性值),狀態的改變將導致行為的變化。
(2) 在程式碼中包含大量與物件狀態有關的條件語句,這些條件語句的出現,會導致程式碼的可維護性和靈活性變差,不能方便地增加和刪除狀態,並且導致客戶類與類庫之間的耦合增強。