五種狀態模式:終極鉤子提醒者延遲事件正交組件轉換到歷史1.終極鉤子模式俗語:老爸對兒子說,你可以按你的特殊方式去做事,但如果你不做,我會做。目的:公共的處理功能放到父狀態,並可以在子狀態中重載,以實現特殊的功能。為什麼叫終極鉤子,因為如果子狀態不處理,總會在父狀態中得到處理,是個終極的處理。問題:父...
五種狀態設計模式:
- 終極鉤子模式
- 提醒者模式
- 延遲事件模式
- 正交組件模式
- 轉換到歷史模式
1.終極鉤子模式
俗語:老爸對兒子說,你可以按你的特殊方式去做事,但如果你不做,我會做。
目的:公共的處理功能放到父狀態,並可以在子狀態中重載,以實現特殊的功能。為什麼叫終極鉤子,因為如果子狀態不處理,總會在父狀態中得到處理,是個終極的處理。
問題:父狀態提供公共一致的事件處理方式,如在GUI設計中,提供一致的界面樣式,為所有的子狀態提供預設的一致界面,如果需要,子狀態也可以重載預設的事件處理方式。
解決方案:使用差異化編程,公共的事件處理放到父狀態中,子狀態中重載特殊行為。子狀態(specific)中的A事件處理重載了父狀態A事件處理,子狀態中的A事件處理就是特殊的事件處理。如果某個子狀態不處理A,則在父狀態中處理A。
圖1.終極鉤子模式
2.提示器模式
俗語:我閑的時候,你通知我做,我就做;我在做事的時候,你就不能通知我了,等我閑時再說。
目的:產生一個事件,併發送給自身,以使狀態圖拓撲更加靈活。
問題:在狀態建模時,一些相關的功能耦合太強,用提示器模式,可以解耦。如定時查詢感測器功能與處理數據功能,當查詢到感測器接完數據時,通過發送一個提示事件讓處理數據功能進行處理。
圖2. 兩個功能模塊
解決方案:兩個功能設計為一個層次狀態機結構,查詢功能設計到父狀態中,處理功能設計到子狀態中,用一個提示器事件(DATA_READY),提示處理功能來處理查詢感測器的得到的數據。
圖3. 提示器模式
可以用提示器模式把一個長任務分解為多個小任務來執行。
3.延遲事件模式
俗語:我很忙,有事我先記下,我閑時,我再按我記下的去做。
目的:通過修改事件的順序來簡化狀態機。用於處理事務。
問題: 當前正在處理一個事務時,因事務是原子性的,不可分割的,這時要是來了新的事件,可能會破壞事務處理的原子性。如ATM終端。
解決方案: 在處理事務時,接收事件並保存到本地隊列中,當本事務處理完時再從本地隊列中召回保存的事件。
圖4. 延遲事件模式
4.正交組件模式
俗語:雖然你是你,我是我,但你聽我的沒錯。
目的:把狀態機做為一個組件來使用,把原來正交區域的獨立關係轉化為主-從關係。
問題: 許多對象包含相對獨立的具有狀態行為的部分,在UML狀態圖中實現方式是,把這種鬆散關聯的功能放到獨立的正交區域,而採用正交區域的解決方法,成本較高。如鬧鐘的功能實現。
解決方案: 使用對象合成來代替正交區域,把行為獨立的兩部分分成兩個狀態機,其中一個包含另一個。正交區域的兩個對象,使一個對象成為容器,包含另一個組件對象,由容器對象負責對組件對象的初始化及調用。通過直接向組件派發事件,容器可以主動觸發組件初始化和狀態轉換;而組件是通過發送事件給容器來通知容器的。
圖5. 正交組件模式
5.轉換到歷史模式
俗語: 我在工作中,當有更重要的事時,我馬上去做,做完後,我會回到我被中斷工作前的狀態。
目的:從某個組合狀態轉換出來時,記住最近的活動子狀態,在返回時,還返回到這個活動子狀態。
問題:在高層組合狀態處理事件時,常常需要處理一些更重要的事件,當處理完時,系統必須返回組合狀態最近的子狀態。
解決方案: 在組合狀態機的屬性中加一個狀態函數變數xxx_history,在狀態機進入某狀態時,保存當前狀態到這個狀態函數變數中。在退出組合狀態後返回時,按照保存在狀態函數變數值,轉換到最後退出組合狀態前的狀態。
圖6.轉換到歷史模式
參考:
【1】Miro Samek《UML狀態圖的實用C/C++設計---嵌入式系統的事件驅動型編程技術》第二版