本文源碼見: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();
}
}
使用Developer
的setState
方法切換不同的狀態,從而實現不同的操作:
高效碼代碼,偶有bug,人非聖賢嘛~
加班熬夜碼代碼,專業寫bug
寫代碼進入天人合一境界,彷彿三頭六臂,碼神附體
總結
這就是狀態模式,將不同的狀態包裝爲不同的類,供其本體引用,從而實現靈活的狀態切換。
看到這裏其實感覺狀態模式和策略模式很像,狀態模式是將不同的狀態對象作爲成員變量給使用者(也稱”環境“),策略模式是將不同的策略對象作爲成員變量給使用者(也稱”環境“)。其實二者還是有些使用上的區別的:
- 策略模式中,作爲成員變量的策略對象通常不會經常變化;而狀態模式在使用者(也稱”環境“)的整個生命週期中會不斷變化。
- 策略模式中,通常並不明確告訴客戶端所選擇的具體策略;而狀態模式中,所處的狀態是明確告知客戶端的;
- 通常策略模式的使用者自己選擇一個具體策略;而狀態模式的使用者(也稱”環境“)通常是被動使用某種狀態。
使用場景
- 一個對象的行爲依賴於它所處的狀態,對象的行爲必須隨着其狀態的改變而改變;
- 對象在某個方法裏依賴一重或多重的條件轉移語句,而且其中有大量代碼的時候。
注意事項
- 狀態模式並未規定哪個角色來進行狀態切換,上邊的例子是由使用者(也稱”環境“)的
setState
方法來切換狀態,而有些情況下是由”狀態“對象本身來切換到下一個狀態。 - 使用者(也稱”環境“)也可以把自己作爲參數傳遞給狀態對象,從而狀態對象也可以調用使用者的方法。