7

ステート マシンのモデル化に関する小さな問題があります。

私は少しの知識工学を行い、状態と状態遷移を決定する原始的な決定論的ルールのセットを「リバースエンジニアリング」しました。

ベストプラクティスが何であるかを知りたい:

  • 状態と状態遷移を厳密にテストして、システムが不確定な状態にならないようにする方法。

  • 状態遷移要件を強制する方法 (たとえば、stateFoo から StateFooBar に直接移動することは不可能であるべきです。つまり、各状態に、遷移可能な状態に関する「知識」を吹き込むことです。

理想的には、可能な限りテンプレートを使用して、クリーンなパターン ベースのデザインを使用したいと考えています。

私はどこかから始める必要があります。

4

7 に答える 7

7

Boost Statechart Libraryを参照してください。

于 2010-04-24T16:54:34.717 に答える
3

まあ、見た目ほど複雑ではありません。ステート マシン コードは非常に単純で短いものです。

状態を変数に格納します。たとえば、myState としましょう。

ステート マシンは switch ステートメントになり、myState 変数の値で分岐して、各状態のコードを実行します。

コードは次のような行でいっぱいになります。

myState = newState;

状態遷移の要件を強制するには、代わりに次のように呼び出される小さなメソッドを追加する必要があります

void DoSafeStateTransition( int newState )
{
// check myState -. newState is not forbidden
// lots of ways to do this
// perhaps nested switch statement

switch( myState ) {

 …

case X:  switch( newState ) 
    case A: case B:  case Z: HorribleError( newState );
    break;

 ...

}

// check that newState is not undetermined

switch( newState ) {

// all the determined states
case A: case B: case C … case Z: myState = newState; break;
default: HorribleError( newState );
}
}
void HorribleError( int newState )
{  printf("Attempt to go from %d to %d - disallowed\n",
       myState, newState );
   exit(1);
}

これは単純で短いので、検査の方が単体テストよりも優れた仕事をすることをお勧めします - 確かにはるかに高速です!

私の考えでは、ユニットテストのポイントは、テストコードがテストされるコードよりも単純であるため、正確性をより簡単に検査してから、複雑なコードをテストするために使用できるということです。多くの場合、ステート マシン テスト コードよりもステート マシン コードをチェックする方が簡単です。単体テストが正しいかどうかほとんどわからない場合、100% の単体テスト パスを報告してもあまり意味がありません。

別の言い方をすれば、ステート マシンをコーディングするのは簡単ですが、正しいマシンを設計するのは難しいということです。単体テストは、設計が正しいかどうかではなく、設計が正しくコーディングされているかどうかのみを示します。

于 2010-04-24T16:48:21.183 に答える
1

テストは、パターンやテンプレートなどとはほとんど関係がありません。すべてのテストケースをキャプチャするには、CppUnit(xUnitファミリーの一部)のようなテストフレームワークをお勧めします。もちろん、その数はステートマシンの複雑さによって異なります。

状態遷移の強制に関する質問は、ステートマシンのクラス設計の中心になります。状態には、遷移する可能性のある子状態のコレクションと、それぞれをトリガーするイベントが含まれると思います。イベントFooにFooBarの子がない場合、それに移行する方法はありません。

私はGoogleの「オブジェクト指向有限状態マシン」でいくつかの設計アイデアを入手し始めたいと思います。

このような問題について考えていたとき、Stateはより複雑なFSMを表す可能性があるため、Compositeデザインパターンがその一部である可能性があると思いました。SimpleStateとCompositeStateを実装として持つStateインターフェースがあります。もう一度やり直して、すべてうまくいくかどうかを確認する必要があります。

于 2010-04-24T16:19:43.913 に答える
1

ステートマシンの使用は時々思い浮かぶものです。私は通常、ravenspointが提案したように実行し、単にswitchステートメントを作成します。ただし、これは、状態が大きすぎない場合にのみ機能します。これはあなたの場合のように聞こえます。それを考慮に入れると、あなたがやりたいことのいくつかを可能にする良いアーキテクチャから始めるのが最善だと思います。私はduffymoの提案を受けて、Googleを試しました。この論文は面白そうだった-オブジェクト指向ステートマシン。やり過ぎかもしれませんが、CppUnitのようなもので簡単にテストできるフレームワークが得られると思います。

グーグル検索からの他のいくつかの良い参考文献

有限状態マシンフレームワーク

オブジェクト指向の有限状態マシン

于 2010-04-24T17:32:37.757 に答える
0

ユニットテスト用の手付かずのアプリケーションのように聞こえます。そこには多くのユニットテストフレームワークがあります。私はたまたまブーストが好きです。

于 2010-04-24T16:18:23.760 に答える
0

ステート デザイン パターンが気に入った場合は、実験を行い、このパターンをライブラリに移動しました: https://code.google.com/p/dpsmlib/

于 2013-11-28T19:57:17.797 に答える
0

古典的な GOF デザイン パターン ステート マシン パターンを探している場合は、wikipediaを参照してください。

このページ (執筆時点) の Java の例をご覧ください。

StateContext使用例からわかるように、クラスがあり、writeNameメソッドを知っているクライアントがあります。実装は次のとおりです。this.myState.writeName(this, name);これは、呼び出しを現在の状態に転送し、それ自体を最初の引数として渡すことを意味します。

を見てください。上記の使用法に一致interface Stateするメソッドがあります。writeNameと の両方を見るStateAStateB、新しい状態を設定するコンテキストにコールバックされます。

これが State パターンのほとんどです。認識すべき唯一のことはStateContext、現在の状態への参照 (C++ ではポインターである必要があります) を含む、その操作に関連するすべてのデータをクラスが保持できることです。すべての状態は集合的にすべての動作を保持しますが、データは保持せず、代わりにコンテキスト内のデータ (およびヘルパー メソッド) を延期します。

私がステート マシンを開発しているとき (私は通常 TDD を使用しています)、状態遷移をわざわざテストすることはありません。

于 2010-04-24T22:46:02.310 に答える