- 人人都懂設計模式:從生活中領悟設計模式(Python實現)
- 羅偉富
- 2209字
- 2019-06-19 15:57:01
第2章 狀態模式
2.1 從生活中領悟狀態模式
2.1.1 故事劇情—人有少、壯、老,水之固、液、氣
一個天氣晴朗的周末,Tony 想去圖書館給自己充充電。于是背了一個雙肩包,坐了一個多小時地鐵,來到了首都圖書館。走進一個閱覽室,Tony 看到一個青澀的小女孩拿著一本中學物理教科書,認真地看著熱力學原理……女孩的容貌像極了 Tony 中學的物理老師,不知不覺Tony想起了他那可愛的老師,想起了那最難忘的一節課……
Viya老師站在一個三尺講臺上,拿著一本教科書,給大家講著水的特性。人有少年、壯年、老年三個不同的階段;少年活潑可愛,壯年活力四射,老年充滿智慧。水也一樣,水有三種不同的狀態:固態—冰,堅硬寒冷,液態—水,清澈溫暖,氣態—水蒸氣,虛無縹緲。更有意思的是水不僅有三種狀態,而且三種狀態還可以相互轉換。冰吸收熱量可以融化成水,水吸收熱量可以汽化為水蒸氣,水蒸氣釋放熱量可以凝固成冰……
雖然時隔近十年,但Viya老師那優雅的容貌和生動的課堂依然歷歷在目!

2.1.2 用程序來模擬生活
水是世界上最奇特的物質之一,不僅滋潤萬物,更是變化萬千!你很難想象冰、水、水蒸氣其實是同一個東西H2O,看到冰你可能會聯想到玻璃、石頭,看到水你可能會聯想到牛奶、可樂,看到水蒸氣你可能會聯想到空氣、氧氣。三個不同狀態下的水好像是三種不同的東西。
水的狀態變化萬千,程序也可以實現萬千的功能。那么如何用程序來模擬水的三種不同狀態及相互轉化呢?
我們從對象的角度來考慮會有哪個類,首先不管它是什么狀態,對象始終是水(H2O),所以會有一個Water類;而它又有三種狀態,我們可以定義三個狀態類:SolidState、LiquidState、GaseousState;從SolidState、LiquidState、GaseousState這三個單詞中我們會發現都有一個State后綴,于是我們會想它們之間是否有一些共性,能否提取出一個更抽象的類,這個類就是狀態類(State)。這些類之間的關系可用圖表示,如圖2-1所示。

圖2-1 水的三態相關類之間的關系
好了,我們已經知道了大概的關系,開始編碼實現吧,在實現的過程中不斷完善。
源碼示例2-1 模擬故事劇情




測試代碼:

輸出結果:

2.2 從劇情中思考狀態模式
2.2.1 什么是狀態模式
Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.
允許一個對象在其內部狀態發生改變時改變其行為,使這個對象看上去就像改變了它的類型一樣。
如水一般,狀態即事物所處的某一種形態。狀態模式是說一個對象在其內部狀態發生改變時,其表現的行為和外在屬性不一樣,這個對象看上去就像改變了它的類型一樣。因此,狀態模式又稱為對象的行為模式。
2.2.2 狀態模式設計思想
從故事劇情的示例中我們知道,水有三種不同狀態:冰、水、水蒸氣。三種不同的狀態有著完全不一樣的外在特性:冰,質堅硬,無流動性,表面光滑;水,具有流動性;水蒸氣,質輕,肉眼看不見,卻存在于空氣中。這三種狀態的特性是不是相差巨大?簡直就不像是同一種東西,但事實卻是不管它在什么狀態,其內部組成都是一樣的,都是水分子(H2O)。這也許就是水的至柔至剛之道吧!
狀態模式的核心思想就是一個事物(對象)有多種狀態,在不同的狀態下所表現出來的行為和屬性不一樣。
2.3 狀態模式的模型抽象
2.3.1 代碼框架
模擬故事劇情的代碼(源碼示例2-1)還是相對比較粗糙的,也有一些不太合理的實現,如:
(1)Water的setTemperature(self,temperature)方法不符合程序設計中的開放封閉原則。雖然水只有三種狀態,但在其他的應用場景中可能會有更多的狀態,如果要再加一個狀態(State),則要在SetTemperature中再加一個if else判斷。
(2)表示狀態的類應該只會有一個實例,因為不可能出現“固態1”“固態2”的情形,所以狀態類的實現要使用單例,關于單例模式會在第5章中進一步講述。
針對這些問題,我們可以對它進行進一步的重構和優化,抽象出狀態模式的框架模型。
源碼示例2-2 狀態模式的框架模型



2.3.2 類圖
源碼示例2-2的代碼框架可用類圖表示,如圖2-2所示。

圖2-2 狀態模式的類圖
State是抽象狀態類(基類),負責狀態的定義和接口的統一。StateA和StateB是具體的狀態類,如故事劇情中的SolidState、LiquidState 、GaseousState。Context是上下文環境類,負責具體狀態的切換。
2.3.3 基于框架的實現
有了上面的代碼框架之后,我們要實現示例代碼的功能就更簡單了。我們假設最開始的示例代碼為Version 1.0,下面看看基于框架的Version 2.0吧。
源碼示例2-3 Version 2.0的實現



這里只要改一下上面測試代碼的第一行就可以了:

讀者可以自己跑一下,會發現輸出結果和之前的是一樣的。
2.3.4 模型說明
1.設計要點
(1)在實現狀態模式的時候,實現的場景狀態有時候會非常復雜,決定狀態變化的因素也非常多,我們可以把決定狀態變化的屬性單獨抽象成一個類 StateInfo,這樣判斷狀態屬性是否符合當前的狀態isMatch時就可以傳入更多的信息。
(2)每一種狀態應當只有唯一的實例。
2.狀態模式的優缺點
優點:
(1)封裝了狀態的轉換規則,在狀態模式中可以將狀態的轉換代碼封裝在環境類中,對狀態轉換代碼進行集中管理,而不是分散在一個個業務邏輯中。
(2)將所有與某個狀態有關的行為放到一個類中(稱為狀態類),使開發人員只專注于該狀態下的邏輯開發。
(3)允許狀態轉換邏輯與狀態對象合為一體,使用時只需要注入一個不同的狀態對象即可使環境對象擁有不同的行為。
缺點:
(1)會增加系統類和對象的個數。
(2)狀態模式的結構與實現都較為復雜,如果使用不當容易導致程序結構和代碼的混亂。
2.4 應用場景
(1)一個對象的行為取決于它的狀態,并且它在運行時可能經常改變它的狀態,從而改變它的行為。
(2)一個操作中含有龐大的多分支的條件語句,這些分支依賴于該對象的狀態,且每一個分支的業務邏輯都非常復雜時,我們可以使用狀態模式來拆分不同的分支邏輯,使程序有更好的可讀性和可維護性。
- OpenDaylight Cookbook
- Mastering Entity Framework
- Python自動化運維快速入門
- Functional Kotlin
- BIM概論及Revit精講
- 低代碼平臺開發實踐:基于React
- Learning OpenStack Networking(Neutron)(Second Edition)
- Create React App 2 Quick Start Guide
- D3.js By Example
- C語言程序設計習題與實驗指導
- 移動增值應用開發技術導論
- Distributed Computing in Java 9
- 零基礎學C語言(第4版)
- C++ System Programming Cookbook
- OpenCV 3.0 Computer Vision with Java