Java設(shè)計(jì)模式之-狀態(tài)模式(State)

一個(gè)物體可能存在多種類型的狀態(tài)妥曲,納悶狀態(tài)之間就會(huì)存在轉(zhuǎn)換的關(guān)系垦写。例如液態(tài)的水,可以氣化成為水蒸氣,也可以固話成為冰塊戴陡,而冰塊可以通過升華直接成為水蒸氣塞绿,水蒸氣反過來通過凝華也能夠化為冰。
下面我畫出了轉(zhuǎn)換過程的狀態(tài)圖恤批,其中省略了升華和凝華的步驟(太多了好麻煩耙煳恰)


狀態(tài)圖

在這個(gè)圖中我們能看到一共有3種狀態(tài):

  • 固體(Solid)
  • 液體(Liquid)
  • 氣體(Gas)

另外還存在4種轉(zhuǎn)換方式:

  • 凝固(Freeze)
  • 融化(Melt)
  • 液化(Liquidation)
  • 氣化(Gasification)

那如果我們想表現(xiàn)Water這一種物質(zhì)在不同狀態(tài)下的轉(zhuǎn)換流程和關(guān)系的話,如果使用丑陋的if語句喜庞,則會(huì)時(shí)代碼陷入萬劫不復(fù)的境地:

if( state == Solid){
    ....
}else if(state == Liquid){
    ...
}

而狀態(tài)模式就是來解決這一類狀態(tài)轉(zhuǎn)換的問題的模式诀浪,它的要求就是將特定狀態(tài)時(shí)的行為和實(shí)現(xiàn),通過狀態(tài)類的方式進(jìn)行定義和封裝延都。當(dāng)一個(gè)類內(nèi)部的狀態(tài)改變時(shí)雷猪,類的行為的具體實(shí)現(xiàn)方式也會(huì)隨之而改變。

下面我們來看一下狀態(tài)模式的UML圖是什么樣子的:


狀態(tài)模式

看UML圖其實(shí)很簡單晰房,就是傳統(tǒng)的類實(shí)現(xiàn)接口求摇,而客戶直接調(diào)用接口。但其實(shí)狀態(tài)模式的關(guān)鍵點(diǎn)在于:

  1. 狀態(tài)的轉(zhuǎn)換需要反饋回調(diào)用方殊者。
  2. 狀態(tài)不需要完全實(shí)現(xiàn)父類定義的所有方法与境。
  3. 狀態(tài)類與宿主類之間的耦合關(guān)系

帶著上面所寫的三個(gè)關(guān)鍵點(diǎn)猖吴,我們來嘗試實(shí)現(xiàn)上面所說的水的狀態(tài)變化過程摔刁。


0. 定義State抽象類

上面說了其實(shí)一共有4種轉(zhuǎn)換方式,那我們就需要在抽象類中定義4個(gè)方法距误,但是由于不是每一種狀態(tài)都會(huì)發(fā)生著4種轉(zhuǎn)換的簸搞,比如說已經(jīng)是水蒸氣了,就無法再進(jìn)行氣化了准潭。所以我們在抽象類中趁俊,仍然實(shí)現(xiàn)了所有的防范,但是方法體都是空的刑然。這與我們在Java設(shè)計(jì)模式之-策略模式中說到的Null Object其實(shí)有著異曲同工之妙寺擂。:

public abstract class WaterState{
    public WaterState freeze(){return null;}
    public WaterState melt(){return null;}
    public WaterState liquidation(){return null;}
    public WaterState gasification(){return null;}
}

然后我們來實(shí)現(xiàn)這三種狀態(tài):

public class Solid extends WaterState{
    public WaterState melt(Water water){
        return water.LIQUID;
    }
}

public class Liquid extends WaterState{
    public WaterState freeze(Water water){
        return water.SOLID;
    }

    public WaterState gasification(Water water){
        return water.GAS;
    }
}

public class Gas extends WaterState{
    public WaterState liquidation(Water water){
        return water.LIQUID;
}

目前我們的狀態(tài)機(jī)已經(jīng)配置完畢了,現(xiàn)在來看一下對應(yīng)的水應(yīng)該如何寫:

public class Water{
    public static final WaterState LIQUID = new Liquid();
    public static final WaterState SOLID = new Solid();
    public static final WaterState GAS = new Gas();

    private WaterState state = new Liquid(); // liquid is default state.
    public getState(){return state;}
    public setState(WaterState state){this.state = state;}

    public void freeze(){
        WaterState tmp = state.freeze(this);
        if(tmp != null)state = tmp;
    }
    public WaterState melt(){
        WaterState tmp = state.melt(this);
        if(tmp != null)state = tmp;
    }
    public WaterState liquidation(){
        WaterState tmp = state.liquidation(this);
        if(tmp != null)state = tmp;
    }
    public WaterState gasification(){
        WaterState tmp = state.gasification(this);
        if(tmp != null)state = tmp;
    }
}

以上我們便實(shí)現(xiàn)了一個(gè)狀態(tài)模式的代碼泼掠,其中關(guān)于上面3點(diǎn)怔软,有如下回復(fù):

  1. 在狀態(tài)機(jī)的轉(zhuǎn)換方法中,返回了需要轉(zhuǎn)換的目標(biāo)態(tài)择镇,直接交給調(diào)用方進(jìn)行使用挡逼;
  2. 狀態(tài)在實(shí)現(xiàn)過程中,只復(fù)寫了1-2個(gè)方法腻豌,并沒有將所有方法都復(fù)寫家坎,因?yàn)橛行┎贿m用于當(dāng)前狀態(tài)嘱能;
  3. 狀態(tài)類于宿主之間通過參數(shù)傳遞的方式進(jìn)行交互,只存在松耦合關(guān)系虱疏;

另外以上例子也可以用Enum來實(shí)現(xiàn)惹骂,這里就不再演示了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末做瞪,一起剝皮案震驚了整個(gè)濱河市对粪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌装蓬,老刑警劉巖著拭,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異矛物,居然都是意外死亡茫死,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門履羞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峦萎,“玉大人,你說我怎么就攤上這事忆首“疲” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵糙及,是天一觀的道長详幽。 經(jīng)常有香客問我,道長浸锨,這世上最難降的妖魔是什么唇聘? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮柱搜,結(jié)果婚禮上迟郎,老公的妹妹穿的比我還像新娘。我一直安慰自己聪蘸,他們只是感情好宪肖,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著健爬,像睡著了一般控乾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娜遵,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天蜕衡,我揣著相機(jī)與錄音,去河邊找鬼设拟。 笑死衷咽,一個(gè)胖子當(dāng)著我的面吹牛鸽扁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播镶骗,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼躲雅!你這毒婦竟也來了鼎姊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤相赁,失蹤者是張志新(化名)和其女友劉穎相寇,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钮科,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唤衫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绵脯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佳励。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蛆挫,靈堂內(nèi)的尸體忽然破棺而出赃承,到底是詐尸還是另有隱情,我是刑警寧澤悴侵,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布瞧剖,位于F島的核電站,受9級特大地震影響可免,放射性物質(zhì)發(fā)生泄漏抓于。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一浇借、第九天 我趴在偏房一處隱蔽的房頂上張望捉撮。 院中可真熱鬧,春花似錦逮刨、人聲如沸呕缭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恢总。三九已至,卻和暖如春睬愤,著一層夾襖步出監(jiān)牢的瞬間片仿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工尤辱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留砂豌,地道東北人厢岂。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像阳距,于是被迫代替她去往敵國和親塔粒。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法筐摘,類相關(guān)的語法卒茬,內(nèi)部類的語法,繼承相關(guān)的語法咖熟,異常的語法圃酵,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • UML概述 UML簡介 UML (Unified Modeling Language)為面向?qū)ο筌浖O(shè)計(jì)提供統(tǒng)一的...
    aron1992閱讀 512評論 0 0
  • 文章部分內(nèi)容轉(zhuǎn)載自:http://blog.csdn.net/zhangerqing 一、設(shè)計(jì)模式的分類 總體來說...
    j_cong閱讀 2,058評論 0 20
  • 當(dāng)晚回到酒店馍管,跟朋友聊起這件事郭赐。他說:你既然來了就該不浪費(fèi)此行,他們身上有很多優(yōu)點(diǎn)的确沸,可以學(xué)習(xí)一下捌锭。擇優(yōu)而取。這樣...
    新雅遇見讀書閱讀 173評論 0 0
  • 對象標(biāo)簽张惹,對象序列化 [[proto]] [[class]] [[extensible]] 原型標(biāo)簽 proto ...
    sunorry閱讀 291評論 0 1