利用狀態樣式(State Pattern)實做狀態機(State Machine)圖的簡單範例

範例-刷票機控制器的狀態圖
圖、範例-刷票機控制器的狀態圖

Description

捷運站的刷票口,平常是處於 “關閉(Locked)” 狀態。當乘客欲進入閘門搭乘捷運時,必須插入票卡後,閘門才會打開(Unlocked 狀態),而乘客通過後閘門即自動關閉。
有兩個異常的事件考量。若乘客未插入票卡而欲進入閘門,則會發出警告聲通知站務人員處理;另一是當乘客已插入票卡,閘門也已開啟,但乘客又再插入一次票卡,此時刷票機會自動退回(Reject)票卡。

先觀察狀態樣式的結構圖

狀態樣式的基本結構圖(GOF, Design Paatern)
圖、狀態樣式的基本結構圖(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 的動作。

文章導覽

   

共有 2 則迴響

  1. 預設行為(default behavior)與 “override” 的考量。
    但不是非得這麼做,也可以宣告為介面或抽象類別(abstract class)。端賴設計的考量。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *