背景
在需求開發(fā)的過程中拍鲤,經(jīng)常會遇到根據(jù)不同的情況作出不同的處理之景。最直接的就是if...else...。
當(dāng)場景特別復(fù)雜時肯夏,判斷if就有些力不從心了。加一個場景需要修改大量的代碼犀暑,這不是一個很好的做法。程序的擴展性特別薄弱烁兰。
舉個栗子:
當(dāng)我們給朋友手機打電話的時候耐亏,朋友的手機就可能出現(xiàn)幾種情況:用戶開機,用戶關(guān)機沪斟,用戶欠費停機广辰,用戶銷戶等。不同的場景產(chǎn)生不同的結(jié)果主之。
狀態(tài)模式
狀態(tài)模式就是用來解決大量不同場景不同行為的模式择吊。
狀態(tài)模式:允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類槽奕。
狀態(tài)模式包含的角色
- Context:環(huán)境類
- State:抽象狀態(tài)類
- ConcreteState:具體狀態(tài)類
示例
日常生活中几睛,我們遇到的最多的帶有狀態(tài)的對象應(yīng)該就是電梯了,電梯有開門粤攒,關(guān)門所森,運行,停止?fàn)顟B(tài)夯接。
public interface ILift {
// 電梯門開狀態(tài)
public void open();
// 電梯關(guān)門狀態(tài)
public void close();
// 電梯移動狀態(tài)
public void run();
// 電梯停止?fàn)顟B(tài)
public void stop();
}
電梯的接口有了焕济,我們可以來看下實現(xiàn)類:
public class Lift implements ILift {
public void open() {
System.out.println("lift is opening");
}
public void close() {
System.out.println("lift is closed");
}
public void run() {
System.out.println("lift run up or down");
}
public void stop() {
System.out.println("lift stopped");
}
}
下面就是電梯類怎么調(diào)用的問題?我們知道狀態(tài)之間是有一定的前提條件的盔几,也就是說狀態(tài)不能隨意轉(zhuǎn)化晴弃。
如果電梯處于open狀態(tài),那它下一個必然是close關(guān)門狀態(tài)逊拍,而不能是run狀態(tài)上鞠;當(dāng)電梯是close狀態(tài),可以是run芯丧,open旗国,stop(沒按樓層)狀態(tài)。如下:
Y:代表可以進行狀態(tài)轉(zhuǎn)化
N:代表不能進行轉(zhuǎn)化
O:代表自己對自己注整,忽略
open | close | run | stop | |
---|---|---|---|---|
open | O | Y | N | N |
close | Y | O | Y | N |
run | N | N | O | Y |
stop | Y | N | Y | O |
由于我們要進行電梯的狀態(tài)轉(zhuǎn)換能曾,因此需要定義出電梯的狀態(tài):
public interface ILift {
public final static int OPEN_STATE = 1;
public final static int CLOSE_STATE = 2;
public final static int RUN_STATE = 3;
public final static int STOP_STATE = 4;
// 設(shè)置電梯狀態(tài)
public void setState(int state);
// 電梯門開狀態(tài)
public void open();
// 電梯關(guān)門狀態(tài)
public void close();
// 電梯移動狀態(tài)
public void run();
// 電梯停止?fàn)顟B(tài)
public void stop();
}
在這邊我們把電梯看成了一個對象度硝,里面有狀態(tài)和狀態(tài)相應(yīng)的動作,可以想象后面我們的調(diào)用代碼基本就是依次調(diào)用Lift類的各個函數(shù)寿冕。
缺點:如果電梯還有其他狀態(tài)(比如通電蕊程,斷電狀態(tài)),則Lift類要修改驼唱,不符合開閉原則藻茂。
根據(jù)狀態(tài)模式,我們思考把狀態(tài)看做一個對象玫恳,更細粒度的切分電梯這個類辨赐,把電梯的每個狀態(tài)當(dāng)成一個類,我們來試驗下:
public abstract class LiftState {
//狀態(tài)轉(zhuǎn)換
private StageChange stageChange;
// 電梯門開狀態(tài)
public abstract void open();
// 電梯關(guān)門狀態(tài)
public abstract void close();
// 電梯移動狀態(tài)
public abstract void run();
// 電梯停止?fàn)顟B(tài)
public abstract void stop();
}
StageChange是狀態(tài)轉(zhuǎn)換類京办,用來進行狀態(tài)的裝換掀序。每個狀態(tài)都有自身的行為,比如Open狀態(tài)有一系列自己的行為:
public class LiftOpenState extends LiftState {
public void open() {
System.out.println("電梯門已經(jīng)開啟");
}
public void close() {
super.stageChange.setLiftState(StageChange.closeState);
super.stageChange.getLiftState().close();
System.out.println("電梯關(guān)門");
}
public void run() {
}
public void stop() {
}
}
狀態(tài)模式通過一系列狀態(tài)自身的流轉(zhuǎn)來達到不同的場景執(zhí)行不同的動作惭婿。
優(yōu)點
- 結(jié)構(gòu)清晰
- 封裝性好