設(shè)計(jì)模式[20]-狀態(tài)模式-State Pattern

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)用
State Pattern.png

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

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘉竟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子洋侨,更是在濱河造成了極大的恐慌舍扰,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件希坚,死亡現(xiàn)場離奇詭異边苹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)裁僧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門个束,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慕购,“玉大人,你說我怎么就攤上這事茬底』Ρ” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵阱表,是天一觀的道長殿如。 經(jīng)常有香客問我,道長最爬,這世上最難降的妖魔是什么涉馁? 我笑而不...
    開封第一講書人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮爱致,結(jié)果婚禮上烤送,老公的妹妹穿的比我還像新娘。我一直安慰自己糠悯,他們只是感情好帮坚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逢防,像睡著了一般叶沛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忘朝,一...
    開封第一講書人閱讀 49,985評(píng)論 1 291
  • 那天灰署,我揣著相機(jī)與錄音,去河邊找鬼局嘁。 笑死溉箕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的悦昵。 我是一名探鬼主播肴茄,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼但指!你這毒婦竟也來了寡痰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤棋凳,失蹤者是張志新(化名)和其女友劉穎拦坠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剩岳,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贞滨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拍棕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晓铆。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勺良,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出骄噪,到底是詐尸還是另有隱情尚困,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布链蕊,位于F島的核電站尾组,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏示弓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一呵萨、第九天 我趴在偏房一處隱蔽的房頂上張望奏属。 院中可真熱鬧,春花似錦潮峦、人聲如沸囱皿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嘱腥。三九已至,卻和暖如春拘悦,著一層夾襖步出監(jiān)牢的瞬間齿兔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來泰國打工础米, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留分苇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓屁桑,卻偏偏與公主長得像医寿,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蘑斧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計(jì)模式匯總 一靖秩、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,922評(píng)論 1 15
  • 1 場景問題# 1.1 實(shí)現(xiàn)在線投票## 考慮一個(gè)在線投票的應(yīng)用竖瘾,要實(shí)現(xiàn)控制同一個(gè)用戶只能投一票沟突,如果一個(gè)用戶反復(fù)...
    七寸知架構(gòu)閱讀 1,937評(píng)論 7 53
  • 1 場景問題# 1.1 報(bào)價(jià)管理## 向客戶報(bào)價(jià),對(duì)于銷售部門的人來講准浴,這是一個(gè)非常重大事扭、非常復(fù)雜的問題,對(duì)不同的...
    七寸知架構(gòu)閱讀 5,070評(píng)論 9 62
  • 1 場景問題 1.1 報(bào)價(jià)管理 向客戶報(bào)價(jià)乐横,對(duì)于銷售部門的人來講求橄,這是一個(gè)非常重大今野、非常復(fù)雜的問題,對(duì)不同的客戶要...
    4e70992f13e7閱讀 3,080評(píng)論 2 16
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,849評(píng)論 25 707