设计模式:状态模式
一、引子?
? ? 狀態(tài)模式自身結(jié)構(gòu)非常簡(jiǎn)單——前面剛剛介紹了幾個(gè)結(jié)構(gòu)比較簡(jiǎn)單的設(shè)計(jì)模式,和他們?
一樣,狀態(tài)模式在具體實(shí)現(xiàn)上留下了可變換的余地。我前面已經(jīng)介紹過(guò)它的孿生兄妹策略模?
式了,大家可以兩者比較著閱讀。本文將會(huì)討論兩者的區(qū)別。?
二、定義與結(jié)構(gòu)?
? ? GOF 《設(shè)計(jì)模式》中給狀態(tài)模式下的定義為:允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它?
的行為。這個(gè)對(duì)象看起來(lái)似乎修改了它的類。看起來(lái),狀態(tài)模式好像是神通廣大——居然能?
夠“修改自身的類” !?
? ? 能夠讓程序根據(jù)不同的外部情況來(lái)做出不同的響應(yīng),最直接的方法就是在程序中將這些?
可能發(fā)生的外部情況全部考慮到,使用if ? else ?語(yǔ)句來(lái)進(jìn)行代碼響應(yīng)選擇。但是這種方法對(duì)?
于復(fù)雜一點(diǎn)的狀態(tài)判斷,就會(huì)顯得雜亂無(wú)章,容易產(chǎn)生錯(cuò)誤;而且增加一個(gè)新的狀態(tài)將會(huì)帶?
來(lái)大量的修改。這個(gè)時(shí)候“能夠修改自身”的狀態(tài)模式的引入也許是個(gè)不錯(cuò)的主意。?
? ? 狀態(tài)模式可以有效的替換充滿在程序中的if ? else 語(yǔ)句:將不同條件下的行為封裝在一?
個(gè)類里面,再給這些類一個(gè)統(tǒng)一的父類來(lái)約束他們。來(lái)看一下?tīng)顟B(tài)模式的角色組成吧:?
1)? 使用環(huán)境(Context)角色:客戶程序是通過(guò)它來(lái)滿足自己的需求。它定義了客戶程序?
? ? 需要的接口;并且維護(hù)一個(gè)具體狀態(tài)角色的實(shí)例,這個(gè)實(shí)例來(lái)決定當(dāng)前的狀態(tài)。?
2)? 狀態(tài)(State)角色:定義一個(gè)接口以封裝與使用環(huán)境角色的一個(gè)特定狀態(tài)相關(guān)的行為。?
3)? 具體狀態(tài)(Concrete State)角色:實(shí)現(xiàn)狀態(tài)角色定義的接口。?
? ? 類圖如下,結(jié)構(gòu)非常簡(jiǎn)單也與策略模式非常相似。?
? ? ? ? ? ? ? ?Context?
? ? ? ? ? ? ? ?request()? ? ? ? ? ? ? ? State?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? handle()?
? ? ? ? ? ? ? ? ? ? ? ? ?ConcreteSate1? ? ? ? ?ConcreteSate2?
? ? ? ? ? ? ? ? ? ? ? ? ?handle()? ? ? ? ? ? ? handle()?
三、實(shí)現(xiàn)?
? ? 由于狀態(tài)模式結(jié)構(gòu)非常簡(jiǎn)單,所以在這里羅列一些反映狀態(tài)模式實(shí)現(xiàn)結(jié)構(gòu)的代碼沒(méi)有什?
么太大的作用。如果你有興趣的話可以按照上面類圖來(lái)編寫一下。?
? ? 在引子中已經(jīng)提到,狀態(tài)模式在具體實(shí)現(xiàn)上存在不同的方案。因此這里重點(diǎn)就這些不同?
的實(shí)現(xiàn)方式進(jìn)行介紹和討論。?
? ? 首先,實(shí)現(xiàn)時(shí)是否將狀態(tài)角色、具體狀態(tài)角色暴露給客戶程序?按照GOF 的建議是不?
希望將狀態(tài)角色暴露給客戶程序的,與客戶程序打交道的僅僅是使用環(huán)境角色,客戶是不知?
道系統(tǒng)是怎么實(shí)現(xiàn)的,更不關(guān)心什么有幾個(gè)具體狀態(tài)。但是當(dāng)使用環(huán)境角色中的初始狀態(tài)緊?
緊依賴于客戶程序時(shí),適乎暴露是在所難免的——這就與策略模式異常相似了!?
? ? 具體狀態(tài)角色中的行為一般是與使用環(huán)境角色密切相關(guān)的。因此這里便有了一個(gè)小細(xì)?
節(jié):我們把使用環(huán)境角色作為參數(shù)傳遞進(jìn)入具體狀態(tài)角色后,是在具體狀態(tài)角色中來(lái)實(shí)現(xiàn)狀?
態(tài)響應(yīng)行為;還是僅僅調(diào)用在使用環(huán)境角色中已經(jīng)實(shí)現(xiàn)了的方法?由于這些行為往往與使用?
環(huán)境角色相關(guān),所以按照《重構(gòu)》一書(shū)的“指導(dǎo)”——后一種實(shí)現(xiàn)方法是比較地道的。?
? ? 從定義可知,狀態(tài)模式是要應(yīng)對(duì)狀態(tài)轉(zhuǎn)換的。那么狀態(tài)的轉(zhuǎn)換在哪里定義呢?你可以選?
擇在使用環(huán)境角色的代碼中來(lái)表現(xiàn)出來(lái),當(dāng)然這便意味著狀態(tài)轉(zhuǎn)變的規(guī)則就固定下來(lái)了。?
GOF ?還給出了另外一種稍微靈活一點(diǎn)的實(shí)現(xiàn)方式:在每一個(gè)具體狀態(tài)角色中來(lái)指定后續(xù)狀?
態(tài)以及何時(shí)進(jìn)行轉(zhuǎn)換。?
? ? 其實(shí)在java? 強(qiáng)大的反射機(jī)制的支持下,我們還可以將狀態(tài)的轉(zhuǎn)換做的更加靈活——我?
們可以將狀態(tài)轉(zhuǎn)換的規(guī)則寫在.xml 等等的配置文件里面甚至是數(shù)據(jù)庫(kù)中,我們姑且叫做狀?
態(tài)轉(zhuǎn)換表。進(jìn)行轉(zhuǎn)換前,根據(jù)狀態(tài)轉(zhuǎn)換表來(lái)讀取下一個(gè)狀態(tài),然后利用反射獲得具體的狀態(tài)?
對(duì)象……。哈哈,看起來(lái)很不錯(cuò)的樣子,只是效率可能低一些——當(dāng)然在企業(yè)應(yīng)用中這應(yīng)該?
不是最重要的。?
? ? 狀態(tài)模式已經(jīng)被我們想象著“實(shí)現(xiàn)”了一番。那么狀態(tài)模式的引入會(huì)給我們的程序帶來(lái)哪?
些優(yōu)勢(shì)呢?前面我們已經(jīng)說(shuō)過(guò):狀態(tài)模式的引入免除了代碼中復(fù)雜而庸長(zhǎng)的邏輯判斷語(yǔ)句。?
而且具體狀態(tài)角色將具體狀態(tài)和它對(duì)應(yīng)的行為封裝了起來(lái),這使得增加一種新的狀態(tài)變得簡(jiǎn)?
單一些。而且如果設(shè)計(jì)合理得話,具體狀態(tài)角色可以被重用(和策略模式一樣,可以考慮使?
用享元模式來(lái)實(shí)現(xiàn))。?
? ? 使用狀態(tài)模式也會(huì)帶來(lái)一些問(wèn)題。每個(gè)狀態(tài)對(duì)應(yīng)一個(gè)具體的狀態(tài)類,使得整體分散,邏?
輯不太清晰。當(dāng)然對(duì)于一個(gè)狀態(tài)非常多的系統(tǒng),狀態(tài)模式帶來(lái)的優(yōu)點(diǎn)還是大于它的缺點(diǎn)的。?
? ? 由上面的分析就可以很明確的知道什么時(shí)候該使用狀態(tài)模式了。下面是GOF 在《設(shè)計(jì)?
模式》中給出的狀態(tài)模式的適用情況:?
? ? 1)? 一個(gè)對(duì)象的行為取決于它的狀態(tài), ?并且它必須在運(yùn)行時(shí)刻根據(jù)狀態(tài)改變它的行為。?
? ? 2)? 一個(gè)操作中含有龐大的多分支的條件語(yǔ)句,且這些分支依賴于該對(duì)象的狀態(tài)。?
四、狀態(tài)VS 策略?
? ? 仔細(xì)對(duì)比狀態(tài)模式和策略模式,難免會(huì)產(chǎn)生疑問(wèn):這兩個(gè)明明是一個(gè)東西嘛!下面我們?
就來(lái)分析下兩者區(qū)別。?
? ? 首先我要聲明,在實(shí)際應(yīng)用中只要能夠使得你的代碼靈活漂亮起來(lái),何必計(jì)較這些方方?
面面的差別呢??
? ? Brandon Goldfedder 在《模式的樂(lè)趣》里是怎么說(shuō)的:“strategy 模式在結(jié)構(gòu)上與state
模式非常相似,但是在概念上,他們的目的差異非常大。區(qū)分這兩個(gè)模式的關(guān)鍵是看行為是?
由狀態(tài)驅(qū)動(dòng)還是由一組算法驅(qū)動(dòng),這條規(guī)則似乎有點(diǎn)隨意,但是在判斷時(shí)還是需要考慮它。?
通常,State? 模式的“狀態(tài)”是在對(duì)象內(nèi)部的,Strategy? 模式的“策略”可以在對(duì)象外部,不過(guò)?
這也不是一條嚴(yán)格、可靠的規(guī)則。”?
? ? 我很同意Brandon ? Goldfedder 的觀點(diǎn)。這兩個(gè)模式的劃分,就在于使用的目的是不同?
的——策略模式用來(lái)處理算法變化,而狀態(tài)模式則是處理狀態(tài)變化(好玄乎阿)。?
? ? 策略模式中,算法是否變化完全是由客戶程序開(kāi)決定的,而且往往一次只能選擇一種算?
法,不存在算法中途發(fā)生變化的情況。從《深入淺出策略模式》中的例子可以很好的看出。?
? ? 而狀態(tài)模式如定義中所言,在它的生命周期中存在著狀態(tài)的轉(zhuǎn)變和行為得更改,而且狀?
態(tài)變化是一個(gè)線形的整體;對(duì)于客戶程序來(lái)言,這種狀態(tài)變化往往是透明的。
總結(jié)
- 上一篇: 利用Azure communicatio
- 下一篇: Resharper 和 Rider 的奇