圖、範例-刷票機控制器的狀態圖
Description
捷運站的刷票口,平常是處於 “關閉(Locked)” 狀態。當乘客欲進入閘門搭乘捷運時,必須插入票卡後,閘門才會打開(Unlocked 狀態),而乘客通過後閘門即自動關閉。
有兩個異常的事件考量。若乘客未插入票卡而欲進入閘門,則會發出警告聲通知站務人員處理;另一是當乘客已插入票卡,閘門也已開啟,但乘客又再插入一次票卡,此時刷票機會自動退回(Reject)票卡。
先觀察狀態樣式的結構圖
圖、狀態樣式的基本結構圖(GOF, Design Pattern)
- 將某類別(Context)的狀態分解為獨立的類別(State)。
- Context 類別會持有一個 Concrete 子類別的個體,以代表現在的狀態。
- State 類別可被定義為抽類類別(Abstract Class)或介面(Interface),負責封裝當 Context 特定狀態時所該展現的行為。
- 每一個子類別均會針對 Context 的某一個狀態來實做出該展現的行為。
- 新增狀態時,只要再根據其狀態來實做一個子類別即可。
利用狀態樣式實做範例狀態機
- TicketGate 類別實做 Lock、Unlock、Alarm、Reject 四個主要的活動(action);TicketGateController 類別繼承了 TicketGate 類別並實做 ticket, pass 兩個事件(event)。
- TicketGateController 有一個參考(reference)指向 TicketGateState Interface, 並將事件的實做委派(delegate)給 TicketGateState 的實體子類別。
- 例如,當 TicketGateController 的狀態為 Locked 時,其參考會指向實現 TicketGateState 介面的 LockedState 個體(Instance)。當 ticket 事件發生時,Controller 內的 ticket() 函式(method) 會委派並同時將本身當參數傳遞給 LockedState 的 ticket() 函式來實做。該函式內部首先會呼叫 Controller 的 setState() 函式,變更狀態為 Unlocked,再呼叫 Controller 的 unlock() 函式,實際執行 Unlock 的動作。
預設行為(default behavior)與 “override” 的考量。
但不是非得這麼做,也可以宣告為介面或抽象類別(abstract class)。端賴設計的考量。
为什么在controller和Ticketgate之间使用继承关系。