1. 程式人生 > 實用技巧 >java設計模式之狀態模式

java設計模式之狀態模式

狀態模式的定義:

  狀態模式也叫作狀態機模式,執行物件在內部狀態發生改變時改變它的行為,物件看起來好像修改了它的類,屬於行為型設計模式。

  狀態模式中類的行為是由狀態決定的,在不同的狀態下有不同的行為。其意圖是讓一個物件在其內部改變的時候,行為也隨之改變。

狀態模式的核心是裝態與行為繫結,不同的狀態對應不同的行為。

狀態模式的應用場景:

  • 行為隨狀態改變而改變的場景。
  • 一個操作中含有龐大的多分支結構,並且這些分支取決於物件的狀態。

狀態模式的UML類圖:

  狀態模式的UML類圖就不畫了,因為它和策略模式的UML類圖基本一致,它們都包含三個角色,

其中環境類角色(Context)分別是負責切換策略和狀態,抽象角色分別是定義不同策略和不同狀態

的行為,具體角色分別是策略的具體實現和狀態的具體實現,唯一的區別是狀態模式在完成某個狀態

的行為之後還有可能會切換到其他狀態。

使用狀態模式實現登入狀態自由切換:

  當我們瀏覽部落格園的文章時,如果我們覺得文章很好,忍不住想評論、收藏。但是如果我們處於未登入的狀態,就會自動跳轉到登入頁面

這裡涉及到的狀態有兩種登入和未登入,行為有評論和收藏。下面使用狀態模式來實現這個邏輯,程式碼如下。

首先建立抽象狀態角色類,定義評論和收藏兩個行為

public abstract class UserState {
    protected AppContext context;

    public
void setContext(AppContext context) { this.context = context; } public abstract void favorite(); public abstract void comment(String comment); }

然後建立未登入狀態類,定義在未登入狀態下,兩種行為的具體實現

public class UnLoginState extends UserState {

    @Override
    public void favorite() {
        this
.switch2login(); this.context.getState().favorite(); } @Override public void comment(String comment) { this.switch2login(); this.context.getState().comment(comment); } private void switch2login(){ System.out.println("跳轉到登入頁!"); this.context.setState(this.context.STATE_LOGIN); } }

建立登入狀態類,定義在登入狀態下,兩種行為的具體實現

public class LoginState extends UserState {
    @Override
    public void favorite() {
        System.out.println("收藏成功!");
    }

    @Override
    public void comment(String comment) {
        System.out.println(comment);
    }
}

建立上下文角色類,根據登入狀態切換具體的行為

public class AppContext {

    public static final UserState STATE_LOGIN = new LoginState();
    public static final UserState STATE_UNLOGIN = new UnLoginState();

    private UserState currentState = STATE_UNLOGIN;

    {
        STATE_LOGIN.setContext(this);
        STATE_UNLOGIN.setContext(this);
    }

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

    public UserState getState(){
        return this.currentState;
    }

    public void favorite(){
        this.currentState.favorite();
    }

    public void comment(String comment){
        this.currentState.comment(comment);
    }
}

最後編寫客戶端測試程式碼。

public class Test {
    public static void main(String[] args) {
        AppContext context = new AppContext();
        context.favorite();
        context.comment("評論:好文章,360個贊");
    }
}

狀態模式和責任鏈模式的區別:

  • 狀態模式和責任鏈模式都能消除if...else分支過多的問題。但是在某些情況下,狀態模式中的狀態可以理解為責任,那麼這種情況下,兩種模式都可以使用。
  • 從定義上來看,狀態模式強調的是一個物件內在狀態的改變,而責任鏈模式強調的是外部節點物件間的改變。
  • 從程式碼實現上來看,兩者最大的區別就是狀態模式的各個狀態物件知道自己要進入的下一個狀態物件,而責任鏈模式並不清楚其下一個節點處理物件,因為鏈式組裝由客戶端負責。

狀態模式和策略模式的區別:

  狀態模式和策略模式的UML類圖架構幾乎完全一樣,但兩者的應用場景是不一樣的。策略模式的多種演算法行為則其一都能滿足,彼此之間是獨立的,使用者可自行更換策略演算法;而

狀態模式的各個狀態之間存在相互關係,彼此之間一定的條件下存在自動切換的效果,並且使用者無法指定狀態,只能設定初始狀態,因為狀態是根據行為而改變的。

狀態模式的優點:

  • 結構清晰:將狀態獨立為類,清楚了冗餘的if...else或switch...case語句,使程式碼更加間接,提高了系統的可維護性。
  • 將狀態轉換現實化:通常物件內部都是使用數值型別來定義狀態的,狀態的切換通過賦值進行表現,不夠直觀;而使用狀態類,當切換狀態時,是以不同的類進行表示的,轉換目的更加明確。
  • 狀態類職責明確且具備擴充套件性。

狀態模式的缺點:

  • 類膨脹,如果一個類的狀態過多,則會造成狀態類過多。
  • 狀態模式的結構和實現都較為複雜,如果使用不當,將導致程式結構和程式碼的混亂。
  • 狀態模式對開閉原則的支援不太友好,如果新增了狀態類,則需要修改負責切換到該類的狀態類。而且修改某個狀態的行為也要修改原始碼。