1 基礎主題:秒錶
下面我們要爲一個機械秒錶建模一個狀態機。這樣一個秒錶通常會有兩個按鈕。
* Start/Stop
* Reset
同時有兩種狀態:
* Stoped: 錶針停留在上次停止時的位置:
o 按下Reset按鈕,錶針回退到0的位置。秒錶保持在Stoped狀態不變。
o 按下Start/Stop按鈕,秒錶轉到Running狀態。
* Running: 錶針在移動,並持續顯示過去的時間:
o 按下Reset按鈕,錶針回退到0的位置,秒錶轉到停止狀態。
o 按下Start/Stop按鈕,轉到Stoped狀態。
下面是其UML圖:
1.1 定義狀態和事件
兩個按鈕可以建模爲兩個事件。進而,定義出必要的狀態和初始狀態。我們從下面的代碼開始,以前的代碼片段會陸續加入其中:
- #include <boost/statechart/event.hpp>
- #include <boost/statechart/state_machine.hpp>
- #include <boost/statechart/simple_state.hpp>
- namespace sc = boost::statechart;
- struct EvStartStop : sc::event< EvStartStop > {};
- struct EvReset : sc::event< EvReset > {};
- struct Active;
- struct StopWatch : sc::state_machine< StopWatch, Active > {};
- struct Stopped;
- // 這裏的simple_state類模板可以接受4個參數:
- // - 第3個參數指定內部的初始狀態,如果有一個這樣的狀態的話。
- // 在這裏,Active有一個內部狀態(Stoped), 所以將這個內部
- // 初始狀態傳給它的基類。
- // - 第4個參數指定是否保留和保留什麼類型歷史
- // Active是最外層的狀態,因此要把它所屬的狀態機類傳給它
- struct Active : sc::simple_state<
- Active, StopWatch, Stopped > {};
- // Stopped 和 Running 都把Active作爲它們的上下文,這使他們嵌入到了Active狀態中。struct Running : sc::simple_state< Running, Active > {};
- struct Stopped : sc::simple_state< Stopped, Active > {};
- // 因爲狀態的上下文必須是一個完整的類型(不能單單是聲明),
- // 所以狀態機必須要在“外層狀態”之間先定義。
- // 也就是說,我們需要從狀態機開始,然後是最外層的狀態,然後是其內部的狀態,如此反覆。
- // 我們可以用廣度或深度方式,再或是以兩都混合的方式來進行定義。
- int main()
- {
- StopWatch myWatch;
- myWatch.initiate();
- return 0;
- }