設(shè)計模式--狀態(tài)模式(State)
前幾天由于忙工作上的事情,每天加班到10點(diǎn)左右才回家,回到家就沒有再開電腦更新東西,今天早了一些回家,開始繼續(xù)更新東西,今天要寫的是狀態(tài)模式,哦,對于一個沒有狀態(tài)的人來說,寫狀態(tài)模式,不知道會寫成什么樣子,反正是一起討論用嘛,能把我所知道的清楚表達(dá)出來已經(jīng)很心滿意足啦。在理解狀態(tài)模式的時候,我總覺得它和策略模式很像很像,有人說它們是孿生兄弟,那我們現(xiàn)在看看狀態(tài)模式到底是一個什么樣的東西。
狀態(tài)模式是對象的一個行為模式,它允許一個對象在其內(nèi)部狀態(tài)改變的時候改變其行為,這個對象看上去就像改了了它的類一樣。
下圖是關(guān)于紅綠燈轉(zhuǎn)換的一個實(shí)現(xiàn)類圖,具體的轉(zhuǎn)換是這樣子的,在初始的情況下,設(shè)定一個燈的狀態(tài),比如是綠燈,那么燈的下一個狀態(tài)則是黃燈,緊接著是紅燈,然后再是綠燈,依次循環(huán);通過改變燈的狀態(tài),改變其行為。
下面是這個類圖的實(shí)現(xiàn)代碼:
package com.plabmedia.state;
public interface LightState {
/**
* 打印當(dāng)前的狀態(tài)
*/
public void print(Light light);}
package com.plabmedia.state;
public class RedLight implements LightState{
@Override
public void print(Light light) {
System.out.println("current state is red");
light.setState(new GreenLight());
}}
package com.plabmedia.state;
public class YellowLight implements LightState{
@Override
public void print(Light light) {
System.out.println("current state is yellow");
light.setState(new RedLight());
}}
package com.plabmedia.state;
public class GreenLight implements LightState {
@Override
public void print(Light light) {
System.out.println("current state is green");
light.setState(new YellowLight());
}}
package com.plabmedia.state;
public class Light {
private LightState state;
public LightState getState() {
return state;
}public void setState(LightState state) {
this.state = state;
}public void print(){
state.print(this);
}public Light(LightState state){
this.state = state;
}}
package com.plabmedia.state;
public class Client {
public static void main(String args[]){
Light light = new Light(new GreenLight());
light.print();
light.print();
light.print();
light.print();
light.print();
light.print();
}}
運(yùn)行結(jié)果:
current state is green
current state is yellow
current state is red
current state is green
current state is yellow
current state is red
上面是對狀態(tài)模式一個小小的實(shí)現(xiàn),這個實(shí)現(xiàn)也僅僅是認(rèn)識級的,在我們實(shí)際應(yīng)用中,如果用到狀態(tài)模式,應(yīng)該比這個要負(fù)責(zé)的多,只是基本的結(jié)構(gòu)是相似的。那我們下面針對狀態(tài)模式做一些討論。
1.在什么情況下使用狀態(tài)模式:
- 一個對象的行為依賴于它所處的狀態(tài),對象的行為必須隨著其狀態(tài)的改變而改變;
- 需要多多重條件轉(zhuǎn)移語句進(jìn)行演化的時候,可以把每個分支封裝成一個狀態(tài)類;現(xiàn)在寫代碼的時候,我是不太喜歡用條件轉(zhuǎn)移語句,特別是最好的那個else語句,我覺得它承擔(dān)的東西太多了,前面不滿足的情況它都要來處理,憑什么啊。
- 誰來定義狀態(tài)的變化:客戶端還是狀態(tài)內(nèi)部決定?這要看當(dāng)時應(yīng)用的環(huán)境,如果狀態(tài)的變化是固定的,我覺得可以再客戶端進(jìn)行設(shè)定;如果狀態(tài)的變化依賴于前一個狀態(tài),比如在工作流系統(tǒng)中,當(dāng)前狀態(tài)是依賴于前一個狀態(tài)的,這需要狀態(tài)內(nèi)部來覺得。
- 狀態(tài)對象創(chuàng)建時機(jī):需要的時候創(chuàng)建?還是事先創(chuàng)建好所有的對象,供需要的時候調(diào)用?這要分系統(tǒng)需要來決定,如果一個系統(tǒng),狀態(tài)變化的順序固定,不那么頻繁,則可以在需要的時候創(chuàng)建所需要的對象;否則,對于頻繁變化的狀態(tài),從性能上將,還是首先創(chuàng)建好各個狀態(tài)對象,供需要時調(diào)用。
- 可以把環(huán)境類傳到具體的狀態(tài)類中,狀態(tài)類在需要的時候調(diào)用環(huán)境類,比如示例中的樣子,其實(shí)在每個狀態(tài)類里面,也可以直接調(diào)用環(huán)境類的print方法,這樣看來,Client只需要初始化環(huán)境類,然后就可以看到它的狀態(tài)在不停地變化。