狀態(tài)模式(分離狀態(tài),選擇實(shí)現(xiàn))

公告

如果您是第一次閱讀我的設(shè)計(jì)模式系列文章蜒灰,建議先閱讀設(shè)計(jì)模式開篇弦蹂,希望能得到您寶貴的建議。

前言

隨著上文 裝飾器模式 提到店鋪老板Bob改良了機(jī)器人的選型過程强窖,價(jià)格又比你的店鋪實(shí)惠銷量得到了顯著增長凸椿。因此,你決定要加大促銷力度翅溺,再一番折扣刺激過后脑漫。煩人的Alice又出現(xiàn)了髓抑,這次又會(huì)提出怎樣的需求呢?

正文

某天下午Alice跑到了你的門店优幸,抱怨他購買的機(jī)器人 “播放歌曲的功能失靈了”吨拍。再也沒法聽到機(jī)器人曼妙的歌聲。

作為一個(gè)“有良心”的賣家网杆,當(dāng)然不能把產(chǎn)品沒做好的事情抖出去羹饰。于是你扛起正義的大旗,保證幫Alice把機(jī)器人修好碳却。

程序員視角

現(xiàn)在我們希望實(shí)現(xiàn)這樣一個(gè)功能 — — “播放音樂”队秩。我們告訴機(jī)器人對(duì)應(yīng)的指令,機(jī)器人就會(huì)默默的為我們查詢歌曲并播放(唱出來)昼浦。

如何實(shí)現(xiàn)

羅列下業(yè)務(wù)事件:

搜索歌曲刹碾、下載歌曲、播放歌曲座柱、暫停歌曲等這些功能都很好實(shí)現(xiàn),但是其狀態(tài)轉(zhuǎn)化卻是相對(duì)比較復(fù)雜的物舒。

比如給機(jī)器人發(fā)口令“播放周杰倫的稻香”:
1色洞、機(jī)器人會(huì)先搜索稻香、周杰倫關(guān)鍵字冠胯。
2火诸、搜到成功后下載到本機(jī)。
3荠察、然后在執(zhí)行播放按鈕置蜀。

但這只是眾多情況中的一種成功情況,還有很多的異常分支需要把控悉盆。

狀態(tài)模式:分離狀態(tài)的行為盯荤,構(gòu)建狀態(tài)轉(zhuǎn)移方程的同時(shí)不用陷入到實(shí)現(xiàn)細(xì)節(jié)中。

這個(gè)例子中狀態(tài)分為幾種:
1焕盟、外部驅(qū)動(dòng) — — 發(fā)送口令播放
2秋秤、內(nèi)部驅(qū)動(dòng) — — 播放口令后的一系列查詢,下載脚翘,播放行為

如果適用的場景全部是外部驅(qū)動(dòng)灼卢,則策略模式命令模式也可以適用。
如果適用的場景全部是內(nèi)部驅(qū)動(dòng)来农,則可構(gòu)建有限狀態(tài)機(jī)鞋真。

``

代碼實(shí)現(xiàn)

狀態(tài)的上層接口

public interface IMusicState {

    // 執(zhí)行音樂相關(guān)操作
    IMusicState handle(ContextState contextState, Music music);

    // 狀態(tài)是內(nèi)部驅(qū)動(dòng)還是外部驅(qū)動(dòng)
    boolean isDependOnUserAction();

}

狀態(tài)管理器(狀態(tài)客戶端)

public class ContextState {

    private IMusicState state;

    public IMusicState getState() {
        return state;
    }

    public void setState(IMusicState state) {
        this.state = state;
    }

    public synchronized void loop(Music music) {
        while (true) {

            if (this.state == null) {
                this.state = new PendingStateImpl();
            }
            this.state = this.state.handle(this, music);
            if (this.state.isDependOnUserAction()) {
                System.out.println("等待用戶再次觸發(fā)狀態(tài)的改變.");
                break;
            }
        }
    }
}

狀態(tài)類

播放狀態(tài) —— 此處僅舉出一例,其余狀態(tài)結(jié)構(gòu)相似

public class PlayStateImpl extends MusicState {
    public PlayStateImpl() {
        System.out.println("構(gòu)建 PlayStateImpl");
    }

    @Override
    public IMusicState handle(ContextState contextState, Music music) {
        if (music.url == null) {
            return new SearchStateImpl();
        }
        if (!music.isDownload) {
            return new DownloadStateImpl();
        }
        return new PauseStateImpl();
    }

    @Override
    public boolean isDependOnUserAction() {
        return false;
    }
}

執(zhí)行結(jié)果

構(gòu)建 PendingStateImpl
構(gòu)建 PlayStateImpl
構(gòu)建 PauseStateImpl
等待用戶再次觸發(fā)狀態(tài)的改變.

總結(jié)

  • 在很多情況下沃于,一個(gè)對(duì)象的行為取決于一個(gè)或多個(gè)動(dòng)態(tài)變化的屬性涩咖,這樣的屬性叫做狀態(tài)海诲,這樣的對(duì)象叫做有狀態(tài)的(stateful)對(duì)象,這樣的對(duì)象狀態(tài)是從事先定義好的一系列值中取出的抠藕。當(dāng)一個(gè)這樣的對(duì)象與外部事件產(chǎn)生互動(dòng)時(shí)饿肺,其內(nèi)部狀態(tài)就會(huì)改變,從而使得系統(tǒng)的行為也隨之發(fā)生變化盾似。
  • 在UML中可以使用狀態(tài)圖來描述對(duì)象狀態(tài)的變化敬辣。

**狀態(tài)態(tài)模式(State Pattern) **:允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來似乎修改了它的類零院。其別名為狀態(tài)對(duì)象(Objects for States)溉跃,狀態(tài)模式是一種對(duì)象行為型模式。

狀態(tài)模式類圖
  • 狀態(tài)模式描述了對(duì)象狀態(tài)的變化以及對(duì)象如何在每一種狀態(tài)下表現(xiàn)出不同的行為告抄。
  • 狀態(tài)模式的關(guān)鍵是引入了一個(gè)抽象類來專門表示對(duì)象的狀態(tài)撰茎,這個(gè)類我們叫做抽象狀態(tài)類,而對(duì)象的每一種具體狀態(tài)類都繼承了該類打洼,并在不同具體狀態(tài)類中實(shí)現(xiàn)了不同狀態(tài)的行為龄糊,包括各種狀態(tài)之間的轉(zhuǎn)換。

在狀態(tài)模式結(jié)構(gòu)中需要理解環(huán)境類與抽象狀態(tài)類的作用:

  • 環(huán)境類實(shí)際上就是擁有狀態(tài)的對(duì)象募疮,環(huán)境類有時(shí)候可以充當(dāng)狀態(tài)管理器(State Manager)的角色炫惩,可以在環(huán)境類中對(duì)狀態(tài)進(jìn)行切換操作。
  • 抽象狀態(tài)類可以是抽象類阿浓,也可以是接口他嚷,不同狀態(tài)類就是繼承這個(gè)父類的不同子類,狀態(tài)類的產(chǎn)生是由于環(huán)境類存在多個(gè)狀態(tài)芭毙,同時(shí)還滿足兩個(gè)條件:

這些狀態(tài)經(jīng)常需要切換筋蓖,在不同的狀態(tài)下對(duì)象的行為不同。因此可以將不同對(duì)象下的行為單獨(dú)提取出來封裝在具體的狀態(tài)類中退敦,使得環(huán)境類對(duì)象在其內(nèi)部狀態(tài)改變時(shí)可以改變它的行為粘咖,對(duì)象看起來似乎修改了它的類,而實(shí)際上是由于切換到不同的具體狀態(tài)類實(shí)現(xiàn)的苛聘。由于環(huán)境類可以設(shè)置為任一具體狀態(tài)類涂炎,因此它針對(duì)抽象狀態(tài)類進(jìn)行編程,在程序運(yùn)行時(shí)可以將任一具體狀態(tài)類的對(duì)象設(shè)置到環(huán)境類中设哗,從而使得環(huán)境類可以改變內(nèi)部狀態(tài)唱捣,并且改變行為。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末网梢,一起剝皮案震驚了整個(gè)濱河市震缭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌战虏,老刑警劉巖拣宰,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件党涕,死亡現(xiàn)場離奇詭異,居然都是意外死亡巡社,警方通過查閱死者的電腦和手機(jī)膛堤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晌该,“玉大人肥荔,你說我怎么就攤上這事〕海” “怎么了燕耿?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長姜胖。 經(jīng)常有香客問我誉帅,道長,這世上最難降的妖魔是什么右莱? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任蚜锨,我火速辦了婚禮,結(jié)果婚禮上慢蜓,老公的妹妹穿的比我還像新娘踏志。我一直安慰自己,他們只是感情好胀瞪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饲鄙,像睡著了一般凄诞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忍级,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天帆谍,我揣著相機(jī)與錄音,去河邊找鬼轴咱。 笑死汛蝙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的朴肺。 我是一名探鬼主播窖剑,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼戈稿!你這毒婦竟也來了西土?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤鞍盗,失蹤者是張志新(化名)和其女友劉穎需了,沒想到半個(gè)月后跳昼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肋乍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年鹅颊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墓造。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堪伍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滔岳,到底是詐尸還是另有隱情杠娱,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布谱煤,位于F島的核電站摊求,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏刘离。R本人自食惡果不足惜室叉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望硫惕。 院中可真熱鬧茧痕,春花似錦、人聲如沸恼除。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豁辉。三九已至令野,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間徽级,已是汗流浹背气破。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留餐抢,地道東北人现使。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像旷痕,于是被迫代替她去往敵國和親碳锈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 設(shè)計(jì)模式匯總 一欺抗、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用殴胧、多...
    MinoyJet閱讀 3,903評(píng)論 1 15
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,504評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器团滥,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 東漢開國皇帝劉秀的祖上是漢景帝劉啟的第六個(gè)兒子長沙定王劉發(fā)竿屹,劉發(fā)是劉秀的五世祖。而劉發(fā)的出生灸姊,則純粹是個(gè)美麗的意外...
    A朔之北閱讀 616評(píng)論 0 3
  • 宮氏理念萬病歸一,疑難多癥輕松治愈 患者王春龍父晶,男哮缺,29歲,鄭州鐵路職工甲喝,于2017年7月20日就診尝苇。 主訴: 1...
    6ef24bfd4b84閱讀 876評(píng)論 0 0