Java設計模式百例 - 狀態模式

本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/state

狀態模式(State Pattern)中,類的行爲是基於它的狀態改變的。這種類型的設計模式屬於行爲型模式。

我們程序猿在碼代碼的時候由於不同的工作狀態,可能寫出質量不一的代碼,並我們不是AI嘛。

  • 早上上班的時候,休息了一夜,精力旺盛,程序猿能夠高效碼代碼,bug也不多;
  • 當熬夜加班的時候,運轉了一天的大腦無比疲憊,寫出的代碼常有bug出沒;
  • 當然,我們也都非常期待在碼代碼的時候能夠達到“天人合一”之境界(雖然這種狀態通常出現在玩遊戲時),沒有煩人的會議、沒有別人的打擾,雖然沒有程序猿鼓勵妹子在側,卻能幾分鐘寫出通常需要幾個小時才能寫出的邏輯,解決近幾天都未解決的問題,可謂“碼神附體”!

例子

如果上述情況用代碼來表述的話,我們來設計一下。

程序猿還是同一個人,但是同一個任務在不同的狀態下,可能會達到不同的效果。

注意上邊這句話,有兩個“同一個”和兩個”不同的“。

人和任務是相同的,是不變的部分;狀態和效果是不同的,是變的部分。按照設計模式的套路,不變的和變化的是要分開來的,從而滿足”開閉“原則,有利於擴展。

不變的是人(類Developer)和任務(方法Developer.develop()),變化的狀態(類XxxState)作爲Developer的成員變量能夠隨時切換看來就可以解決這個問題。

由於狀態是變化的,因此需要不同的類XxxState來描述,其方法XxxState.develop()正好可以靈活實現不同狀態下的工作效果。

完美!最後還有一個,按照設計模式的通常套路,同一類變化的類要抽象爲接口或抽象類,並提供統一的接口方法,從而做到”面向接口“編程,以應對變化。

設計完畢,那就開工:

Developer.java

public class Developer {
    private State state;

    public Developer(State state) {
        this.state = state;
    }

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

    public void develop() {
        state.coding();
    }
}

Developer維護有State的引用,並提供setState(State)方法切換狀態。

State.java

public interface State {
    void coding();
}

EffectiveState.java

public class EffectiveState implements State {
    public void coding() {
        System.out.println("高效碼代碼,偶有bug,人非聖賢嘛~");
    }
}

ExhaustedState.java

public class ExhaustedState implements State {
    public void coding() {
        System.out.println("加班熬夜碼代碼,專業寫bug");
    }
}

TianRenHeYiState.java

public class TianRenHeYiState implements State {
    public void coding() {
        System.out.println("寫代碼進入天人合一境界,彷彿三頭六臂,碼神附體");
    }
}

狀態模式

不同的狀態有不同的實現效果,通過State抽象出統一的接口。

測試一下:

Client.java

public class Client {
    public static void main(String[] args) {
        Developer developer = new Developer(new EffectiveState());
        developer.develop();
        developer.setState(new ExhaustedState());
        developer.develop();
        developer.setState(new TianRenHeYiState());
        developer.develop();
    }
}

使用DevelopersetState方法切換不同的狀態,從而實現不同的操作:

高效碼代碼,偶有bug,人非聖賢嘛~
加班熬夜碼代碼,專業寫bug
寫代碼進入天人合一境界,彷彿三頭六臂,碼神附體

總結

這就是狀態模式,將不同的狀態包裝爲不同的類,供其本體引用,從而實現靈活的狀態切換。

看到這裏其實感覺狀態模式和策略模式很像,狀態模式是將不同的狀態對象作爲成員變量給使用者(也稱”環境“),策略模式是將不同的策略對象作爲成員變量給使用者(也稱”環境“)。其實二者還是有些使用上的區別的:

  • 策略模式中,作爲成員變量的策略對象通常不會經常變化;而狀態模式在使用者(也稱”環境“)的整個生命週期中會不斷變化。
  • 策略模式中,通常並不明確告訴客戶端所選擇的具體策略;而狀態模式中,所處的狀態是明確告知客戶端的;
  • 通常策略模式的使用者自己選擇一個具體策略;而狀態模式的使用者(也稱”環境“)通常是被動使用某種狀態。

使用場景

  • 一個對象的行爲依賴於它所處的狀態,對象的行爲必須隨着其狀態的改變而改變;
  • 對象在某個方法裏依賴一重或多重的條件轉移語句,而且其中有大量代碼的時候。

注意事項

  • 狀態模式並未規定哪個角色來進行狀態切換,上邊的例子是由使用者(也稱”環境“)的setState方法來切換狀態,而有些情況下是由”狀態“對象本身來切換到下一個狀態。
  • 使用者(也稱”環境“)也可以把自己作爲參數傳遞給狀態對象,從而狀態對象也可以調用使用者的方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章