doアクティビティ
状態に入ったところで実行されるのが入場時アクション。状態から出るときに実行されるのが退場時アクション。それに対してdoアクティビティは、その状態にはいったあと、その状態にいる間、実行されるもの、である。
この状態マシン図の場合、2通りの動き方がある。
- 状態1に入場すると、まず入場時アクション1を実行し、それに続いてdoアクティビティ1が実行される。それが終わると状態1のままそこに留まっていて、イベント2が起きると、退場時アクション1が実行されて、状態2に遷移する。
- 状態1に入場すると、まず入場時アクション1を実行し、それに続いてdoアクティビティ1が実行される。それが終わる前に、イベント2が起きると、doアクティビティが中断されたあと、退場時アクション1が実行されて、状態2に遷移する。
例を使って説明する。湯沸し中状態に入ったところで、入場時アクションとして「湯沸しランプを点灯」したあと、「湯を沸かす」を開始する。それが終わると、左側のヌル遷移(完了遷移)があるので、退場時アクションとして「湯沸しランプを消灯」したあと、ヌル遷移をたどって保温中になる。また、湯沸し状態では、保温ボタンを押すことができ、「湯を沸かす」を中断して「湯沸しランプを消灯」したあと保温中に遷移する。
いっぽう、保温中に入ると、「保温ランプを点灯」したあと、「保温する」を開始する。保温するは終わりがなく、ヌル遷移(完了遷移)が設定されていない。中断することはでき、湯沸しボタンが押されれば、湯沸し中状態に遷移する。
この例のように、doアクティビティで実行することは、しばらく時間がかかるもので、中断できるものである。「湯を沸かす」のように終わりがあるものもあれば、「保温する」のように終わりがないものもある。
UMLで決められているアクションやイフェクトなどの振る舞いの中で、中断できると決められているのは、このdoアクティビティだけである。
doアクティビティは実装依存であり、ハードウェアで実行されたり、別タスクで実行されたり、さまざまな実装が考えられる。状態マシン的には、doアクティビティ実行中もイベントが到着したら直ちに状態遷移がおきることを想定しており、doアクティビティの中断は一瞬でできるよう実装されることが望まれる。
もし、いつでも時間遅れなく確実に中断することが難しい環境の場合は、doアクティビティを使わずに状態マシン図を設計したほうが良いだろう。
完了遷移
状態を起点とする遷移で、明示的なイベントが指定されていないものを、完了遷移と呼ぶ。完了遷移は完了イベントで発火し、完了イベントは単純状態の場合、次のときに起きる。
- 入場時アクションもdoアクティビティもない場合は、その状態に入ったとき
- 入場時アクションがあってdoアクティビティがない場合は、入場時アクションが終わったとき
- doアクティビティがある場合は、doアクティビティが終わったとき
まとめ
アクションは、同期実行される関数呼び出しや文の実行です。その関数や文の実行が終わるまでは次のイベントは取り出されず、イベントキューに積まれたままです。アクションの実行に時間がかかりすぎると、イベントキューにたまったイベントの取り出しが遅れてしまうため、お客様から見て、応答性が悪いと思われたりする可能性があります。また、イベントを取りこぼさないよう、イベントキューをそれなりに深くしておく必要もあります。
それに対し、アクティビティは、非同期実行されるものです。UMLではアクティビティを表現するのにアクティビティ図というフローチャートの進化形みたいなものを使って表現します。状態マシン側から見ると、アクティビティをキックするだけで、アクティビティの終了は待ちません。なので、すぐ次のイベント待ちに入ります。お湯を沸かし始めても、すぐ次のイベント待ちに入るので、保温ボタンが押されてもすぐに処理できます。
アクティビティは、一般には、他のタスクや他のプロセッサやタイマ割り込みやハードウェアで実現されるもので、状態マシンを実行しているコンテキスト(タスク)とは違うもので実装されることが多いです。そして、他のコンテキストで実行されるアクティビティが終わると、それがなんらかのしくみで、もとの状態マシンに知らされるようになっていたりします。
UMLでは状態マシンをどう実装するかは何も決められておらず、それと同じくアクティビティもどう実装するかは何も決められておらず、当然、状態マシンからアクティビティをどうキックするか、アクティビティの終了をどう状態マシンに伝えるか、どう実装されているか何も決められていません。
同じタスクでやっても、複数のタスクでやっても、割り込みを使っても、他のプロセッサを使っても、ハードウェアがやっても、なにをどうやってもOKです。
わたしのいる職場では、他のコンテキストのことを考えたくない、また、どう実装するかの議論を避けたい、という理由で、doアクティビティを使わないで状態マシン図を描くルールになっていて、doアクティビティの終了通知に相当するものも、イベントで届くように描いています。
いっぽう、営業や企画のひとにとっては、その状態にいる間はずっと保温しつづける、とかその状態にはいると、ずっと水を加熱しつづけていて、お湯が沸いたら、湯沸かし中の状態を出てくる、という表現はとてもわかりやすいため(ソフトでどう実装するかなんてそういう人たちは考えないから)分析フェーズであれば、doアクティビティを使っても良いかな、という感じもします。