1.狀態(tài)模式簡介
狀態(tài)模式(State Pattern)模式是行為型(Behavioral)設(shè)計(jì)模式失仁,允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來似乎修改了它的類注竿。這個(gè)定義很拗口,很抽象,等看完了例子晦雨,我們在總結(jié)時(shí),再換一個(gè)方式來描述隘冲。
當(dāng)一個(gè)對(duì)象有多種狀態(tài)闹瞧,狀態(tài)之間可以互相轉(zhuǎn)化,每種狀態(tài)的行為不相同展辞,就可以使用狀態(tài)模式奥邮。對(duì)于客戶端而言,不需要知道對(duì)象當(dāng)前的狀態(tài)罗珍,不需要關(guān)心狀態(tài)變遷的邏輯洽腺。
狀態(tài)模式一共有三種角色:
(1) Context(環(huán)境類):環(huán)境類又稱為上下文類,持有狀態(tài)對(duì)象覆旱,具備切換狀態(tài)的行為蘸朋。
(2) State(抽象狀態(tài)類):定義一個(gè)接口,用以封裝環(huán)境(Context)對(duì)象的一個(gè)特定的狀態(tài)所對(duì)應(yīng)的行為扣唱。
(3) ConcreteState(具體狀態(tài)類):每一個(gè)具體狀態(tài)類都實(shí)現(xiàn)了環(huán)境(Context)的一個(gè)狀態(tài)所對(duì)應(yīng)的行為藕坯。
2. 狀態(tài)模式舉例
下面模擬風(fēng)扇換擋的操作团南,簡單起見,風(fēng)扇僅有off(關(guān)閉)炼彪、low(低擋)吐根、high(高擋)三個(gè)擋位(狀態(tài));每個(gè)擋位對(duì)應(yīng)的行為都不同辐马。
序號(hào) | 類名 | 角色 | 說明 |
---|---|---|---|
1 | FanContext | Context | 上下文類 |
2 | FanState | State | 抽象狀態(tài)類 |
3 | FanOffState | ConcreteState | 具體狀態(tài)類拷橘,風(fēng)扇處于OFFf狀態(tài) |
4 | FanLowState | ConcreteState | 具體狀態(tài)類,風(fēng)扇處于LOW狀態(tài) |
5 | FanHighState | ConcreteState | 具體狀態(tài)類喜爷,風(fēng)扇處于HIGH狀態(tài) |
6 | StateMain | 客戶端 | 演示調(diào)用 |
1. FanContext 上下文類
public class FanContext {
public final static FanState OFF = new FanOffState();
public final static FanState LOW = new FanLowState();
public final static FanState HIGH = new FanHighState();
private FanState fanState;
// 初始化時(shí)冗疮,風(fēng)扇位于OFF擋
public FanContext() {
fanState = OFF;
fanState.setFanContext(this);
}
public FanState getFanState() {
return fanState;
}
public void setFanState(FanState fanState) {
this.fanState = fanState;
// 換擋時(shí),把context設(shè)入
fanState.setFanContext(this);
}
public void turnOff() {
fanState.turnOff();
}
public void shiftHigh() {
fanState.shiftHigh();
}
public void shiftLow() {
fanState.shiftLow();
}
}
2. FanState 抽象狀態(tài)類贞奋,定義了狀態(tài)對(duì)應(yīng)的抽象行為
public abstract class FanState {
protected FanContext fanContext;
public void setFanContext(FanContext fanContext) {
this.fanContext = fanContext;
}
// 關(guān)風(fēng)扇
abstract void turnOff();
// 調(diào)到高擋
abstract void shiftHigh();
// 調(diào)到低擋
abstract void shiftLow();
}
3. FanOffState赌厅,具體狀態(tài)類
/**
* 具體狀態(tài)類,風(fēng)扇處于OFF狀態(tài)轿塔;可以調(diào)到低擋或者調(diào)到高擋特愿。
*/
public class FanOffState extends FanState {
@Override
public void turnOff() {
System.out.println("風(fēng)扇關(guān)閉");
}
@Override
public void shiftHigh() {
// 把上下文切換到FanHighState
super.fanContext.setFanState(FanContext.HIGH);
// 調(diào)用FanHighState,調(diào)至高擋
super.fanContext.getFanState().shiftHigh();
}
@Override
public void shiftLow() {
// 把上下文切換到FanLowState
super.fanContext.setFanState(FanContext.LOW);
// 調(diào)用FanLowState勾缭,調(diào)至低擋
super.fanContext.getFanState().shiftLow();
}
}
4. FanLowState揍障,具體狀態(tài)類
/**
* 具體狀態(tài)類,風(fēng)扇處于LOW狀態(tài)俩由;可以關(guān)閉或者調(diào)到高擋毒嫡。
*/
public class FanLowState extends FanState {
@Override
public void turnOff() {
// 把上下文切換到FanOffState,并調(diào)用其關(guān)閉操作幻梯。
super.fanContext.setFanState(FanContext.OFF);
super.fanContext.getFanState().turnOff();
}
@Override
public void shiftHigh() {
// 把上下文切換到FanHighState兜畸,并調(diào)用其升擋操作。
super.fanContext.setFanState(FanContext.HIGH);
super.fanContext.getFanState().shiftHigh();
}
@Override
public void shiftLow() {
System.out.println("風(fēng)扇調(diào)整到了低擋");
}
}
**5.FanHighState碘梢,具體狀態(tài)類 **
/**
* 具體狀態(tài)類咬摇,風(fēng)扇處于HIGH狀態(tài);可以關(guān)閉或者調(diào)到低擋煞躬。
*/
public class FanHighState extends FanState {
@Override
public void turnOff() {
// 把上下文切換到FanOffState肛鹏,并調(diào)用其關(guān)閉操作。
super.fanContext.setFanState(FanContext.OFF);
super.fanContext.getFanState().turnOff();
}
@Override
public void shiftHigh() {
System.out.println("風(fēng)扇調(diào)整到了高擋");
}
@Override
public void shiftLow() {
// 把上下文切換到FanLowState恩沛,并調(diào)用其降擋操作在扰。
super.fanContext.setFanState(FanContext.LOW);
super.fanContext.getFanState().shiftLow();
}
}
4. StateMain 演示類
public class StateMain {
public static void main(String[] args) {
// 初始化上下文
FanContext fanContext = new FanContext();
// 調(diào)到高
fanContext.shiftHigh();
// 調(diào)到低擋
fanContext.shiftLow();
// 關(guān)閉
fanContext.turnOff();
}
}
結(jié)果輸出
風(fēng)扇調(diào)整到了高擋
風(fēng)扇調(diào)整到了低擋
風(fēng)扇關(guān)閉
3. 總結(jié)
狀態(tài)模式將一個(gè)對(duì)象在不同狀態(tài)下的不同行為封裝到一個(gè)個(gè)類中,通過設(shè)置不同的狀態(tài)對(duì)象雷客,讓上下文類具備不同的行為芒珠。具體到我們舉得例子中,風(fēng)扇在不同的擋位具有不同的行為搅裙,例子中每個(gè)擋位都封裝成了一個(gè)類妓局;通過設(shè)置FanContext中不同的FanState总放,從而是FanContext具備了不同的行為。
狀態(tài)模式封裝了狀態(tài)的轉(zhuǎn)換規(guī)則好爬,將某個(gè)狀態(tài)有關(guān)的行為都封裝在一個(gè)類中,只需要在上下文類中注入不同的狀態(tài)類甥啄,環(huán)境類就可以有不同的行為存炮,避免了大量寫if else 語句。
狀態(tài)模式的使用必然會(huì)增加系統(tǒng)中的類和對(duì)象的數(shù)目蜈漓,設(shè)計(jì)難度變大穆桂,系統(tǒng)運(yùn)行開銷變大;如果要新增狀態(tài)類融虽,則必然要修改負(fù)責(zé)狀態(tài)轉(zhuǎn)換的代碼享完。
策略模式和狀態(tài)模式
狀態(tài)模式和策略模式的類圖看起來簡直就是一樣的,都如下圖所示有额。狀態(tài)模式和策略模式的實(shí)現(xiàn)方法非常類似般又,都是利用多態(tài)把一些操作分配到一組相關(guān)的簡單的類中。
適用場景不同:這一點(diǎn)就是狀態(tài)和策略的不同巍佑,對(duì)象的狀態(tài)茴迁,例如工作流、界面的按鈕操作萤衰、電梯的狀態(tài)堕义,其核心是狀態(tài)的變遷;策略常用的場景比如電商的折扣策略等脆栋。
客戶端感知不同:在狀態(tài)模式中倦卖,狀態(tài)的變遷是由對(duì)象的內(nèi)部條件決定,客戶端只需關(guān)心其接口椿争,不必關(guān)心其狀態(tài)對(duì)象的創(chuàng)建和轉(zhuǎn)化怕膛;而策略模式里,采取何種策略由客戶端決定的丘薛。
策略模式的連接:http://www.reibang.com/p/90759e153ac9
(完)