3

GUI をステート マシンとして実装したいと考えています。これを行うことにはいくつかの利点といくつかの欠点があると思いますが、これはこの質問のトピックではありません。

これについて読んだ後、C++ でステート マシンをモデル化するいくつかの方法を見つけ、2 に固執しましたが、どの方法が GUI モデリングに適しているかわかりません。

  1. 次のメソッドを使用して、ステート マシンを状態のリストとして表します。

    • OnEvent(...);
    • OnEnterState(...);
    • OnExitState(...);

    IからStateMachine::OnEvent(...)イベントを転送しCurrentState::OnEvent(...)、ここで遷移を行うかどうかの決定が行われます。移行時に を呼び出しCurrentState::OnExitState(...)NewState::OnEnterState()CurrentState = NewState;

    このアプローチでは、状態はアクションと密接に結合されますがState、1 つの状態から複数の状態に移動でき、異なる遷移に対して異なるアクションを実行する必要がある場合、複雑になる可能性があります。

  2. 次のプロパティを持つ遷移のリストとしてステート マシンを表します。

    • InitialState
    • FinalState
    • OnEvent(...)
    • DoTransition(...)

    Iから、ステート マシンと同じ値を持つStateMachine::OnEvent(...)すべての遷移にイベントを転送します。遷移条件が満たされた場合、ループが停止し、メソッドが呼び出されて に設定されます。InitialStateCurrentStateDoTransitionCurrentStateTransition::FinalState

    このアプローチTransitionを使用すると、非常に単純になりますが、遷移カウントの数が非常に多くなる可能性があります。また、ある状態がイベントを受け取ったときに実行されるアクションを追跡することも難しくなります。

GUIモデリングにはどのアプローチが良いと思いますか? 私の問題に適した他の表現を知っていますか?

4

5 に答える 5

3

3 番目のオプションは次のとおりです。

  • ステート マシンを遷移行列として表す
    • 行列の列インデックスは状態を表します
    • 行列の行インデックスは a symbol(以下を参照) を表します
    • マトリックス セルは、遷移先の状態を表します。これは、新しい状態または同じ状態の両方である可能性があります
    • すべての状態にOnEventは、symbol

実行結果を返すFromStateMachine::OnEvent(...)イベントが転送されます。次に、現在の状態と返されたシンボルに基づいて、State::OnEventsymbolStateMachine

  • 別の状態に遷移する必要がある、または
  • 現在の状態が保持されます
  • オプションで、遷移が行われOnExitStateOnEnterState対応する状態に対して呼び出される場合

3 つの状態と 3 つのシンボルの行列の例

0 1 2
1 2 0
2 0 1

この例では、マシンがいずれかの状態(0,1,2)にあり、State::OnEventシンボル0(マトリックスの最初の行) を返す場合、同じ状態のままです。

2行目は、現在の状態がで0あり、返されたシンボルが状態である場合、状態1への遷移が行われることを示しています1。state 1-> state2および state 2-> state の場合0

同様に、3 行目は、シンボル2、状態0-> 状態2、状態1-> 状態0、状態2-> 状態について、1

これのポイント:

  1. 州の数symbolsよりもはるかに少ない可能性があります。
  2. 州はお互いを認識していません
  3. すべての遷移は一点から制御されるため、シンボルDB_ERRORを別の方法で処理したいNETWORK_ERROR場合は、遷移テーブルを変更するだけで、状態の実装には触れないでください。
于 2012-12-07T13:59:33.297 に答える
1

私は個人的にあなたが言った最初の方法を好みます。2 つ目は非常に直感に反し、複雑すぎると思います。状態ごとに 1 つのクラスを用意するのは単純で簡単です。次に、OnEnterState で正しいイベント ハンドラーを設定し、OnExitState でそれらを削除すると、コードがクリーンになり、すべてが対応する状態に自己完結するため、簡単に読み取ることができます。

また、状態が行うことはすべて状態自体の内部で完全に可視化されるため、呼び出す適切なイベント ハンドラーまたはプロシージャを選択するための巨大な switch ステートメントを使用する必要がなくなり、状態マシン コードが短くシンプルになります。

最後になりましたが、このコーディング方法は、ステート マシンの描画から使用する言語への正確な変換です。

于 2012-12-07T13:46:08.903 に答える
1

これがあなたが期待しているような答えかどうかはわかりませんが、私はそのようなステート マシンを単純な方法で処理することに慣れています。

列挙型 (可能な状態) の状態変数を使用します。GUI のすべてのイベント ハンドラーで、たとえば switch ステートメントを使用して状態値をテストします。それに応じて必要な処理を行い、状態の次の値を設定します。

軽量で柔軟。コードを規則的に保つことで、コードが読みやすくなり、「形式的」になります。

于 2012-12-07T13:38:33.930 に答える
0

この種のコードには、本当に単純なアプローチを好みます。

  • 状態の列挙。
  • 各イベント ハンドラーは、実行するアクションを決定する前に現在の状態をチェックします。switchアクションは、ステートメントまたはifチェーン内の単なる複合ブロックであり、次の状態を設定します。
  • アクションが数行以上になるか、再利用する必要がある場合は、別のヘルパー メソッドへの呼び出しとしてリファクタリングします。

この方法では、追加のステート マシン管理メタデータ構造がなく、そのメタデータを管理するコードもありません。ビジネス データと移行ロジックのみ。また、アクションは、現在の状態を含むすべてのメンバー変数を直接検査および変更できます。

欠点は、1 つの状態にローカライズされたデータ メンバーを追加できないことです。非常に多数の状態がない限り、これは実際の問題ではありません。

以前の設定について仮定を立て、状態遷移の前に不変条件を復元する状態終了動作を作成するのではなく、各状態へのエントリですべての UI 属性を常に構成すると、より堅牢な設計につながることもわかりました。これは、トランジションの実装に使用するスキームに関係なく適用されます。

于 2012-12-07T14:20:37.857 に答える
0

ペトリネットを使用して目的の動作をモデル化することも検討できます。これは、考えられるすべてのシナリオを正確に判断し、デッドロックを防ぐことができるため、より複雑な動作を実装する場合に適しています。

このライブラリは、GUI を制御するステート マシンを実装するのに役立つ場合があります: PTN エンジン

于 2017-10-01T22:06:58.593 に答える