読者です 読者をやめる 読者になる 読者になる

Boost.statechart まとめ

C++

 これまで書いてきた Boost.statechart のまとめです。

まずこれまで書いたのは以下の 6 エントリです。本記事を入れて全 7 エントリとなります。

Boost.statechart 事始め
Boost.statechart でイベントを受け取る
Boost.statechart で状態のネストを定義する。
Boost.statechart で現在の状態を確認する。
Boost.statechart で複数状態を持つマシンを実装する。
Boost.statechart で CSV を読む。

主に参照したドキュメントはこちら。
The Boost Statechart Library

 状態のモデリングは「State パターン」というそれっぽい名前がついているぐらいなのでプログラマなら誰もが一度は意識した事があるかと思います。

 で、僕もご多分に漏れず状態をそれっぽく表現しようと試みてきたわけですが、モデリング能力が及ばずいつもぐちゃぐちゃになってしまいがちでした。ところが今回 Boost.statechart を使って、そういう事態をずいぶんと和らげられたんじゃないのかなと思います。もちろん、ライブラリなんて山ほどあるので Boost.statechart こそ至高だと言うつもりはありませんのであしあからず。

 とゆーわけで、Boost.statechart を使って得られたメリットを本まとめ記事のコンテンツにしようと思います。

1. 「状態」に明示的に型を与えることができる。
 そもそも状態を表現するために、手抜きでやろうとすると、状態を識別するために俺々ルールで強行突破してしまいがちです。例えば


・メンバ変数 Data * data_; が NULL だったら○○モード、そうでなければ××モードとする。
enum Mode { ,,, } を定義して、メンバ変数 Mode mode_; の値を逐次確認すること。
などなど。
 で、こういう方法は俺々ルールに過ぎないので、デメリットが大きいのですよね。「ある状態のときには呼んでいいけど別の状態のときには呼んではいけないメソッド」とかを定義しにくい。あ、これは "状態ごとにスコープを分けられる" というフレーズで強調した方が良かったかな。もちろんがんばって枠組みを構築すればできますけど、面倒だしあんまりやりませんからね。

2.「イベント」に明示的に型を与えることができる。
 これは見過ごしちゃ行けないメリットです。手抜きで状態遷移を含むプログラムを書こうとすると、状態遷移用のメンバ関数をひとつ作る、という手段を選びがちだと思います。この方法だと状態の切り替え時に行いたい処理を状態に応じて特殊化しにくい上、イベントそのものの情報量が固定されてしまう傾向にあると思います。Boost.statechart ではイベントを型で与えるので、イベントそのものにメンバを持つ事が出来ます。また、状態とイベントの組み合わせに応じた特殊な制御を追加したい場合でも影響範囲を必要最小限にすることができます。

3.「状態遷移」を明示的に書ける。
 ある状態 A から別の状態 B に遷移するってことはそりゃーもう大変なコトなんです。リソース確保/解放やら何やら、過渡状態でやるべき処理が集中するので、それらを安全かつ冗長性なく遂行せにゃならんのですね。それらを記述するルールが提供されていて、このルールが比較的 "堅い" おかげでプログラムがスパゲッティになりにくいように感じました。例えばこんなの。


・状態 s0 のときにイベント A が来たら状態 s1 に移る
・状態 s0 のときにイベント A が来たら react メンバ関数で遷移先を決める。
・状態 s0 のときにイベント A が来たら○○を処理して状態遷移しない。
・状態 s0 のときにイベント A が来たら状態 s1 に移って s1 にイベント A を渡す。
・状態 s0 のときにイベント A が来たらどういう対応をするのかの判断権を親に譲る。
・状態 s0 のときにイベント A が来たら別のイベントキューにイベントを溜める。
・状態 s0 のときにイベント A が来たら何もしない。
 これくらい多彩な反応のしかたをサポートする状態マシンを作ろうとすると相当大変ですよね。"そんなの、全部使わないでしょ" と言われそうですが、実際どれも無いと困るレベルだと思います。

4.状態をネストしたり複数持ったりできる。
 これも有難いです。しかも 1〜3 のメリットを全て踏まえた上で、こうした表現ができるわけです。特にネストは状態マシンのモデルを図化する際によく用いられる概念でありながら、コードに落とす過程でそれなりのテクニックが要求されるポイントだと思います。ライブラリで吸収されてるべきポイントですね。