04

20

[状態マシン図] 状態マシン図を実装する

2014.04.20(21:22)

状態マシン図の設計モデルができたら、今度はそれを実装に変換しよう。

状態マシン図を実装する方法はいろいろあり、それぞれ一長一短がある。ここではもっとも簡単な形の実装例をひとつあげてみよう。

状態マシンは、「今の状態と発生したイベントから、次の状態を決定する」関数のモデル、と考えることができる。今回紹介する実装例は、

今の状態と 発生したイベントを引数にとり、次の状態を返す関数、
次の状態 = イベントの処理(今の状態, 発生したイベント);
という関数を呼びだして、状態を更新しつづけるものである。組込みシステムでは、RTOSから1つイベントを受信してはこの関数を呼び出すイベントループを構成する。以下のような実装になる。

状態 s = 最初の状態;
while(true) {
  イベント e = イベントを受信();
  s = イベントの処理(s, e);
}

これで状態マシンを実装することができる。具体的な状態マシン図と実装を見てみよう。実装に使う言語はC言語にしよう。

code102.png
typedef enum State { S1,S2 } State;
typedef enum Event { E1,E2 } Event;

void main(void)
{
  State s = S1;
  while(true) {
    Event e = イベント受信();
    s = イベント処理(s,e);
  }
}

State イベント処理(State s,Event e)
{
  if ((s == S1) && (e == E2)) {
    s = S2;
  } else if ((s == S2) && (e == E1) && g1()) {
    a1();
    s = S1;
  }
  return s;
}

イベント処理関数は、引数eに、E1でもE2でもないイベントが渡されたら、それを無視して、今の状態と同じ状態を返す。

また、S2を起点とする遷移にはガード条件g1()が設定されている。S2の状態にいるときに、イベントE1がおきたとき、g1()が成立したならば、S1に遷移することを示している。実装を確認してほしい。

各遷移にアクションを設定し、各状態に入場時アクション、退場時アクションを設定してみよう。

code152.png
typedef enum State { Undefined,S1,S2 } State;
typedef enum Event { E1,E2 } Event;

void main(void)
{
  State s = Undefined;
  a0();
  s = S1;
  entry1();
  while(true) {
    Event e = イベント受信();
    s = イベント処理(s,e);
  }
}

State イベント処理(State s,Event e)
{
  if ((s == S1) && (e == E2)) {
    exit1();
    a2();
    s = S2;
    entry2();
  } else if ((s == S2) && (e == E1) && g1()) {
    exit2();
    a1();
    s = S1;
    entry1();
  }
  return s;
}

StateにUndefinedという値を追加した。a0()を実行する間は、
状態はS1でもS2でもない、Undefinedの状態である。

entry1()とexit1()を実行する間は、状態はS1であり、
entry2()とexit2()を実行する間は、状態はS2となるように、
アクションと状態を更新する順序を工夫している。

Undefinedの状態は、履歴疑似状態の実現でも必要となるので、
状態マシンの実装はいつも、Undefinedの状態から始まるように
しておけばよい。

このように、
次の状態 = イベントの処理(今の状態, 発生したイベント);
という関数呼出しを繰り返せば、状態マシンは実装することができる。

コンポジット状態ではイベントの処理の関数を入れ子にしてゆけばよい。直交状態では、領域ごとにイベントの処理の関数を作り、それぞれの領域ごとに状態を覚えてゆけばよい。履歴疑似状態では、その領域または、その領域以下のすべての状態を覚えておくための変数を別に用意し、履歴が設定されている状態を退場するときに、その変数に覚えておいて、次回入場するときにそれを戻せばよい。

より複雑な状態マシン図も実装してみてほしい。

また、状態マシン図の別の実装としては、GoF23パターンの1つ、Stateパターンが有名である。

参考記事
  1. [状態マシン図] 遷移 と イベント[ガード]/アクション
    http://saltheads.blog134.fc2.com/blog-entry-141.html
  2. [状態マシン図] UML2.0 状態機械 モデル
    http://saltheads.blog134.fc2.com/blog-entry-138.html
  3. [Haskell] Haskellで 状態マシンを書く
    http://saltheads.blog134.fc2.com/blog-entry-80.html
プロフィール

島敏博

Shima Toshihiro 島敏博
信州アルプスハイランド在住。HaskellとElixirが好き。組み込みソフトウェアアーキテクト、C++プログラマ、山歩き、美術館巡り、和食食べ歩き、日本赤十字社救急法指導員、インデックス投資、クラシック音楽、SESSAME会員、状態マシン設計、モデル駆動開発、ソフトウェアプロダクトライン、Rubyist、実践ビジネス英語

■ ツイッター
http://twitter.com/saltheads
■ Facebook
http://www.facebook.com/saltheads
■ Qiita
http://qiita.com/saltheads

印刷する場合は、ブラウザの印刷メニューではなく、このページの上から3cmくらいの青いところにある、「印刷」を押してみてください。少しうまく印刷できます。まだ完全ではないのですが、これで勘弁してください。


カテゴリ
最新記事
月別アーカイブ
最新コメント
検索フォーム
リンク
sessame
RSSリンクの表示