設(shè)計模式-狀態(tài)模式

介紹

狀態(tài)模式和策略模式是一對雙胞胎艳汽,他們都屬于行為設(shè)計模式领曼。狀態(tài)模式和策略模式都是為具有多種可能情形設(shè)計的模式布持,把不同的處理情形抽象為一個相同的接口题暖,符合對擴展開放捉超,對修改封閉的原則。策略模式封裝了一組相關(guān)算法拼岳,它允許Client在運行時使用可互換的行為;狀態(tài)模式幫助一個類在不同的狀態(tài)顯示不同的行為侧啼。狀態(tài)模式封裝了對象的狀態(tài)痊乾,而策略模式封裝算法或策略哪审。因為狀態(tài)是跟對象密切相關(guān)的虑瀑,它不能被重用;而通過從Context中分離出策略或算法叽奥,我們可以重用它們朝氓。
狀態(tài)模式(State Pattern) 允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類待德。對象的行為依賴于它的狀態(tài)(屬性)将宪,并且可以根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為橡庞。

TCP協(xié)議中的三次握手和四次斷開也可以使用狀態(tài)模式來實現(xiàn)扒最。

結(jié)構(gòu)圖

這里寫圖片描述

時序圖

這里寫圖片描述

案例

我就用工作日的上班時間來舉例子
6種狀態(tài)

  1. 23點到早上7點
  2. 7點到9點
  3. 9點到12點
  4. 12點到13點
  5. 13點到18點
  6. 18點到23點

State 抽象類

public abstract class State {
    
    public abstract void handle(WorkDay workDay);
    
    public void changeState(WorkDay workDay){
        State state = null;
        if (23 < workDay.getHour() || workDay.getHour() <= 7) {
            state = new SleepState();
        }
        if (7 < workDay.getHour() && workDay.getHour() <= 9) {
            state = new EarlyMorningState();
        }
        if (9 < workDay.getHour() && workDay.getHour() <= 12) {
            state = new MorningState();
        }
        if (12 < workDay.getHour() && workDay.getHour() <= 13) {
            state = new MiddayState();
        }
        if (13 < workDay.getHour() && workDay.getHour() < 18) {
            state = new AfternoonState();
        }
        if (18 < workDay.getHour() && workDay.getHour() <= 23) {
            state = new NightState();
        }
        
        workDay.setState(state);
        workDay.doWork();
    }
}

23點到早上7點睡覺狀態(tài)SleepState

public class SleepState extends State {

    @Override
    public void handle(WorkDay workDay) {
        if (23 < workDay.getHour() || workDay.getHour() <= 7) {
            System.out.println("現(xiàn)在是" + workDay.getHour() + "點确封,晚上睡覺時間!");
        } else {
            changeState(workDay);
        }
    }

}

**7點到9點清晨狀態(tài)EarlyMorningState **

public class EarlyMorningState extends State {

    @Override
    public void handle(WorkDay workDay) {
        if (7 < workDay.getHour() && workDay.getHour() <= 9) {
            System.out.println("現(xiàn)在是" + workDay.getHour() + "點爪喘,清晨秉剑,準備上班!");
        } else {
            changeState(workDay);
        }
    }

}

9點到12點上午上班狀態(tài)MorningState

public class MorningState extends State{
    @Override
    public void handle(WorkDay workDay) {
        if (9 < workDay.getHour() && workDay.getHour() <= 12) {
            System.out.println("現(xiàn)在是" + workDay.getHour() + "點侦鹏,上午工作時間!");
        } else {
            changeState(workDay);
        }
    }
}

12點到13點中午休息狀態(tài)MiddayState

public class MiddayState extends State {
    @Override
    public void handle(WorkDay workDay) {
        if (12 < workDay.getHour() && workDay.getHour() <= 13) {
            System.out.println("現(xiàn)在是"+workDay.getHour()+"點略水,中午休息時間!");
        } else {
            workDay.setState(new NightState());
            workDay.doWork();
        }
    }
}

13點到18點下午工作狀態(tài)AfternoonState

public class AfternoonState extends State {

    @Override
    public void handle(WorkDay workDay) {
        if (13 < workDay.getHour() && workDay.getHour() <= 18) {
            System.out.println("現(xiàn)在是" + workDay.getHour() + "點渊涝,下午工作時間!");
        } else {
            changeState(workDay);
        }
    }
}

18點到23點晚上下班狀態(tài)NightState

public class NightState extends State {

    @Override
    public void handle(WorkDay workDay) {
        if (18 < workDay.getHour() && workDay.getHour() <= 23) {
            System.out.println("現(xiàn)在是" + workDay.getHour() + "點床嫌,晚上下班時間!");
        } else {
            changeState(workDay);
        }
    }
}

工作日類WorkDay

public class WorkDay {
    private State state = new NightState();
    private int hour;

    public State getState() {
        return state;
    }

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

    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }
    
    public void doWork(){
        state.handle(this);
    }
}

調(diào)用類Client

public class Client {
    public static void main(String[] args) {
        WorkDay workDay = new WorkDay();
        for (int i = 0; i < 55; i++) {
            workDay.setHour(i%24);
            workDay.doWork();
        }
    }
}

運行結(jié)果


這里寫圖片描述

總結(jié)

在很多情況下鳖谈,一個對象的行為取決于一個或多個動態(tài)變化的屬性缆娃,這樣的屬性叫做狀態(tài),這樣的對象叫做有狀態(tài)的(stateful)對象龄恋,這樣的對象狀態(tài)是從事先定義好的一系列值中取出的凶伙。當一個這樣的對象與外部事件產(chǎn)生互動時,其內(nèi)部狀態(tài)就會改變显押,從而使得系統(tǒng)的行為也隨之發(fā)生變化乘碑。
環(huán)境類實際上就是擁有狀態(tài)的對象金拒,環(huán)境類有時候可以充當狀態(tài)管理器(State Manager)的角色,可以在環(huán)境類中對狀態(tài)進行切換操作资铡。
抽象狀態(tài)類可以是抽象類笤休,也可以是接口症副,不同狀態(tài)類就是繼承這個父類的不同子類,狀態(tài)類的產(chǎn)生是由于環(huán)境類存在多個狀態(tài)闹啦,同時還滿足兩個條件: 這些狀態(tài)經(jīng)常需要切換辕坝,在不同的狀態(tài)下對象的行為不同圣勒。因此可以將不同對象下的行為單獨提取出來封裝在具體的狀態(tài)類中,使得環(huán)境類對象在其內(nèi)部狀態(tài)改變時可以改變它的行為挚歧,對象看起來似乎修改了它的類吁峻,而實際上是由于切換到不同的具體狀態(tài)類實現(xiàn)的在张。由于環(huán)境類可以設(shè)置為任一具體狀態(tài)類帮匾,因此它針對抽象狀態(tài)類進行編程瘟斜,在程序運行時可以將任一具體狀態(tài)類的對象設(shè)置到環(huán)境類中,從而使得環(huán)境類可以改變內(nèi)部狀態(tài)痪寻,并且改變行為橡类。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顾画,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子研侣,更是在濱河造成了極大的恐慌义辕,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件璧函,死亡現(xiàn)場離奇詭異基显,居然都是意外死亡,警方通過查閱死者的電腦和手機库继,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門宪萄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榨惰,“玉大人,你說我怎么就攤上這事居凶。” “怎么了抹估?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵弄兜,是天一觀的道長挨队。 經(jīng)常有香客問我蒿往,道長,這世上最難降的妖魔是什么腾夯? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任蔬充,我火速辦了婚禮饥漫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘积蜻。我一直安慰自己彻消,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布丙笋。 她就那樣靜靜地躺著御板,像睡著了一般牛郑。 火紅的嫁衣襯著肌膚如雪井濒。 梳的紋絲不亂的頭發(fā)上列林,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天希痴,我揣著相機與錄音春感,去河邊找鬼。 笑死嫩实,一個胖子當著我的面吹牛窥岩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颂翼,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼朦乏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吃引?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎姑蓝,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旭愧,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡输枯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年桃熄,在試婚紗的時候發(fā)現(xiàn)自己被綠了瞳收。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碉京。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖界弧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情划栓,我是刑警寧澤条获,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布月匣,位于F島的核電站奋姿,受9級特大地震影響称诗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寓免,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一撕予、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧实抡,春花似錦欢策、人聲如沸踩寇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荣茫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間计露,已是汗流浹背票罐。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留该押,地道東北人蚕礼。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓奠蹬,卻偏偏與公主長得像囤躁,于是被迫代替她去往敵國和親冀痕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

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

  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是狀態(tài)模式 模式的結(jié)構(gòu) 典型代碼 代碼示例 狀態(tài)模式和策略模式的區(qū)別 優(yōu)點和缺點...
    w1992wishes閱讀 749評論 0 6
  • 定義 狀態(tài)模式狸演,又稱為狀態(tài)對象模式(Pattern of Object for States)言蛇,狀態(tài)模式是對象的行...
    步積閱讀 1,132評論 0 1
  • 設(shè)計模式匯總 一、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復使用宵距、多...
    MinoyJet閱讀 3,922評論 1 15
  • 前言 Android的設(shè)計模式系列文章介紹腊尚,歡迎關(guān)注,持續(xù)更新中: Android的設(shè)計模式-設(shè)計模式的六大原則一...
    四月葡萄閱讀 7,855評論 5 6
  • 今天我們來學習一種行為型模式满哪,狀態(tài)模式(State Pattern)婿斥。 模式定義 允許一個對象在其內(nèi)部狀態(tài)改變時改...
    HJXANDHMR閱讀 4,481評論 5 12