本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/state
在狀態(tài)模式(State Pattern)中,類的行為是基于它的狀態(tài)改變的弟蚀。這種類型的設計模式屬于行為型模式。
我們程序猿在碼代碼的時候由于不同的工作狀態(tài),可能寫出質量不一的代碼,并我們不是AI嘛筷笨。
- 早上上班的時候,休息了一夜,精力旺盛啊片,程序猿能夠高效碼代碼,bug也不多玖像;
- 當熬夜加班的時候,運轉了一天的大腦無比疲憊齐饮,寫出的代碼常有bug出沒捐寥;
- 當然,我們也都非常期待在碼代碼的時候能夠達到“天人合一”之境界(雖然這種狀態(tài)通常出現(xiàn)在玩游戲時)祖驱,沒有煩人的會議握恳、沒有別人的打擾,雖然沒有程序猿鼓勵妹子在側捺僻,卻能幾分鐘寫出通常需要幾個小時才能寫出的邏輯乡洼,解決近幾天都未解決的問題崇裁,可謂“碼神附體”!
例子
如果上述情況用代碼來表述的話束昵,我們來設計一下拔稳。
程序猿還是同一個人,但是同一個任務在不同的狀態(tài)下锹雏,可能會達到不同的效果巴比。
注意上邊這句話,有兩個“同一個”和兩個”不同的“礁遵。
人和任務是相同的轻绞,是不變的部分;狀態(tài)和效果是不同的佣耐,是變的部分政勃。按照設計模式的套路,不變的和變化的是要分開來的兼砖,從而滿足”開閉“原則奸远,有利于擴展。
不變的是人(類Developer
)和任務(方法Developer.develop()
)掖鱼,變化的狀態(tài)(類XxxState
)作為Developer
的成員變量能夠隨時切換看來就可以解決這個問題然走。
由于狀態(tài)是變化的,因此需要不同的類XxxState
來描述戏挡,其方法XxxState.develop()
正好可以靈活實現(xiàn)不同狀態(tài)下的工作效果芍瑞。
完美!最后還有一個褐墅,按照設計模式的通常套路拆檬,同一類變化的類要抽象為接口或抽象類,并提供統(tǒng)一的接口方法妥凳,從而做到”面向接口“編程竟贯,以應對變化。
設計完畢逝钥,那就開工:
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)
方法切換狀態(tài)。
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("加班熬夜碼代碼,專業(yè)寫bug");
}
}
TianRenHeYiState.java
public class TianRenHeYiState implements State {
public void coding() {
System.out.println("寫代碼進入天人合一境界哗咆,仿佛三頭六臂蜘欲,碼神附體");
}
}
不同的狀態(tài)有不同的實現(xiàn)效果,通過State
抽象出統(tǒng)一的接口晌柬。
測試一下:
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
方法切換不同的狀態(tài)姥份,從而實現(xiàn)不同的操作:
高效碼代碼郭脂,偶有bug,人非圣賢嘛~
加班熬夜碼代碼澈歉,專業(yè)寫bug
寫代碼進入天人合一境界展鸡,仿佛三頭六臂,碼神附體
總結
這就是狀態(tài)模式闷祥,將不同的狀態(tài)包裝為不同的類娱颊,供其本體引用,從而實現(xiàn)靈活的狀態(tài)切換凯砍。
看到這里其實感覺狀態(tài)模式和策略模式很像箱硕,狀態(tài)模式是將不同的狀態(tài)對象作為成員變量給使用者(也稱”環(huán)境“),策略模式是將不同的策略對象作為成員變量給使用者(也稱”環(huán)境“)悟衩。其實二者還是有些使用上的區(qū)別的:
- 策略模式中剧罩,作為成員變量的策略對象通常不會經(jīng)常變化;而狀態(tài)模式在使用者(也稱”環(huán)境“)的整個生命周期中會不斷變化座泳。
- 策略模式中惠昔,通常并不明確告訴客戶端所選擇的具體策略;而狀態(tài)模式中挑势,所處的狀態(tài)是明確告知客戶端的镇防;
- 通常策略模式的使用者自己選擇一個具體策略;而狀態(tài)模式的使用者(也稱”環(huán)境“)通常是被動使用某種狀態(tài)潮饱。
使用場景
- 一個對象的行為依賴于它所處的狀態(tài)来氧,對象的行為必須隨著其狀態(tài)的改變而改變;
- 對象在某個方法里依賴一重或多重的條件轉移語句香拉,而且其中有大量代碼的時候啦扬。
注意事項
- 狀態(tài)模式并未規(guī)定哪個角色來進行狀態(tài)切換,上邊的例子是由使用者(也稱”環(huán)境“)的
setState
方法來切換狀態(tài)凫碌,而有些情況下是由”狀態(tài)“對象本身來切換到下一個狀態(tài)扑毡。 - 使用者(也稱”環(huán)境“)也可以把自己作為參數(shù)傳遞給狀態(tài)對象,從而狀態(tài)對象也可以調用使用者的方法盛险。