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