State Pattern
將狀態封裝成獨立的類別,並把動作 delegate 到目前的狀態物件,讓物件行為隨著內在狀態改變而改變。
使用情境
系統中有些狀態以及操作,而操作會依據狀態不同而不同,通常這時候能畫出 state machine。
依據 state machine,我們可能就會寫出這樣的 code:
1 | // pseudo code |
operation()
通常是 state machine 裡的動作。
不只 operation()
裡有很多 if,還可能有很多像 operation()
的 function。如果其中有 state 需求變動,或者要加入新的 state,改這段 code 頭就痛了……
State Pattern 是將 state 封裝成一個個 class(封裝會變動的部份)。將在不同 state 要做的操作,分別放到每個 state class 中,並透過將操作 delegate 給 state object 做,來消除原本 code 裡一堆的 if。
來點例子
用《深入淺出設計模式》的例子,糖果機與狀態 class 們的 code 擷取如下:
1 | public interface State { |
1 | public class NoQuarterState implements State { |
其他的 state class 就不一一列舉啦~依此推類。
1 | public class GumballMachine { |
糖果機將操作 delegate 給 state object 做,state object 會做事並且改變糖果機的狀態。
UML
Context::request()
call state.operation1()
,將事情 delegate 給 state object 做。在糖果機的例子裡,GumballMachine
就是 Context
。
由誰處理狀態轉換?
狀態轉換可以在 state object 做,也可以在 context 做,糖果機的例子是由 state object 做狀態轉換。
一般原則是狀態轉換是固定的時候,適合在 context 做,而轉換會在 runtime 因為條件不同而有不同時適合在 state object 做。
在 state object 轉換狀態的缺點是會讓 state object 們互相依賴,解決這問題的方式之一是讓 state object 可以透過 context 取得其他 state object,也就是糖果機的 state getters。
與 Strategy Pattern 比較
State pattern 跟 Strategy pattern 的 UML 根本長得一樣。兩個 pattern 的差異在於「意圖」,也可以說是出發點、想達到的目的。
State pattern 將行為封裝在一堆 state object 中,context 隨著狀態不同將動作 delegate 給其中一個 state object。Strategy pattern 則是有很多 algorithm 可以選,通常由使用 algorithm 的使用者(使用 strategy 的 code)決定用哪一個。Strategy 提供了 algotithm 選擇上的彈性但由使用者主導。State 則以狀態為主,狀態改變會導致行為改變。