FSM状態の実装手法
-
28-09-2019 - |
質問
FSM(編集:有限状態マシン)状態をどのように実装しますか?私は通常、一連の関数、ディスパッチャー、現在の実行状態を示すスレッドのようなFSMについて考えます。つまり、私は状態を表す機能/ファンサーへの呼び出しをブロックします。
ちょうど今私は別のスタイルで1つを実装しました。ここでは、機能(オブジェクト)を持つ状態をまだ表していますが、スレッドはただ state->step()
方法。できるだけ早く戻そうとします。状態が終了し、移行が行われるべき場合、それはそれに応じてそれを示します。機能はほとんどのように見えるので、私はこれを「ポーリング」スタイルと呼びます。
void step()
{
if(!HaveReachedGoal)
{
doWhateverNecessary();
return; // get out as fast as possible
}
// ... test perhaps some more subgoals
indicateTransition();
}
FSM内のFSMであることを知っています。
かなり単純な感じがしますが、特定の利点があります。スレッドがブロックされている、またはある種のものに保持されている間while (!CanGoForward)checkGoForward();
ループは面倒で扱いにくい場合がありますが、投票はデバッグがはるかに簡単に感じられました。それは FSM
オブジェクトはステップごとにコントロールを取り戻し、デバッグ情報を出すのは簡単です。
まあ私は私の質問から逸脱しています:どうやって 君 FSMの状態を実装しますか?
解決
州の設計パターンは、FSMを実装する興味深い方法です。
http://en.wikipedia.org/wiki/state_pattern
FSMを実装する非常にクリーンな方法ですが、FSMの複雑さに応じて乱雑になる可能性があります(ただし、状態の量ではありません)。ただし、利点は次のとおりです。
- コードの複製を排除します(特に/elseステートメントの場合)
- 新しい州で拡張する方が簡単です
- クラスはより良い結束力があるため、関連するすべてのロジックは1つの場所にあります。これにより、コードがテストを簡単に書くことができます。
このサイトにはJavaおよびC ++の実装があります。
他のヒント
私がFSMSを実装するフライングスパゲッティモンスターのスタイル(FSMスタイルFSMS)と呼ばれるものが常にあります:ロッサを使用してください goto
s。例えば:
state1:
do_something();
goto state2;
state2:
if (condition) goto state1;
else goto state3;
state3:
accept;
とても素敵なスパゲッティコード:-)
私はそれをテーブルとして、メモリ内のフラット配列、各セルは状態です。 CVSソースをご覧ください 放棄されたDFAプロジェクト. 。にとって 例:
class DFA {
DFA();
DFA(int mychar_groups,int mycharmap[256],int myi_state);
~DFA();
void add_trans(unsigned int from,char sym,unsigned int to);
void add_trans(unsigned int from,unsigned int symn,unsigned int to);
/*adds a transition between state from to state to*/
int add_state(bool accepting=false);
int to(int state, int symn);
int to(int state, char sym);
void set_char(char used_chars[],int);
void set_char(set<char> char_set);
vector<int > table; /*contains the table of the dfa itself*/
void normalize();
vector<unsigned int> char_map;
unsigned int char_groups; /*number of characters the DFA uses,
char_groups=0 means 1 character group is used*/
unsigned int i_state; /*initial state of the DFA*/
void switch_table_state(int first,int sec);
unsigned int num_states;
set<int > accepting_states;
};
しかし、これは非常に具体的なニーズのためでした(正規表現の一致)
最初のFSMプログラムを覚えています。私は非常にシンプルでCでそれを書きました スイッチ 声明。ある状態から別の状態に切り替えるか、次の状態に切り替えることは自然に思えました。
それから私はaを使用するために進みました テーブルルックアップアプローチ. 。このアプローチを使用して、非常に一般的なコーディングスタイルを書くことができました。しかし、要件が変更されたときに数回捕まったので、いくつかの追加のイベントをサポートする必要があります。
私は最近FSMを書いていません。私が書いた最後のものは、私が使用したC ++のCommsモジュールのためでした」状態設計パターン「Aと一緒に」コマンドパターン" (アクション)。
複雑な状態マシンを作成している場合は、チェックアウトすることをお勧めします SMC - ステートマシンコンパイラ。これにより、ステートマシンのテキスト表現が必要になり、お好みの言語にまとめられます。これは、Java、C、C ++、C#、Python、Ruby、Scalaなどをサポートしています。