質問
一般的なものを探しています
- 最適化
- 正しさ
- 拡張性
現在のC ++階層状態マシンの実装に関するアドバイス。
サンプル
variable isMicOn = false
variable areSpeakersOn = false
variable stream = false
state recording
{
//override block for state recording
isMicOn = true //here, only isMicOn is true
//end override block for state recording
}
state playback
{
//override block for state playback
areSpeakersOn = true //here, only areSpeakersOn = true
//end override block for state playback
state alsoStreamToRemoteIp
{
//override block for state alsoStreamToRemoteIp
stream = true //here, both areSpeakersOn = true and stream = true
//end override block for state alsoStreamToRemoteIp
}
}
goToState(recording)
goToState(playback)
goToState(playback.alsoStreamToRemoteIp)
実装
現在、HSMは、各状態が子として可変数の状態を持つことができるツリー構造として実装されています。
各状態には、可変数の「オーバーライド」が含まれます。基本値をオーバーライドするブロック(std :: map内)。ルート状態では、ステートマシンにはいくつかのデフォルト値に初期化された変数(関数、プロパティ...)のセットがあります。子状態に入るたびに、「オーバーライド」のリストが表示されます。親状態の同じ名前の変数と値を置き換える変数と値を定義します。明確にするためにオリジナルを更新しました。
変数の参照
実行時に、現在の状態はスタックに保存されます。
変数が参照されるたびに、最も高いオーバーライドを探して、またはオーバーライドがない場合はデフォルト値を探して、下方へのスタックウォークが実行されます。
状態の切り替え
単一の状態フレームが切り替えられるたびに、状態はスタックにプッシュされます。
状態が切り替わるたびに、現在の状態からルート状態に至るツリーの下降をトレースします。次に、現在のトレースが前のトレースと一致するまで、ターゲット状態からルート状態へのツリーの下降を行います。これら2つのトレースが交わる場所で交差点を宣言します。次に、ターゲット状態に切り替えるために、ソースから降りて、交点に到達するまでスタックから状態フレームをポップします。次に、ターゲットノードまで上昇し、状態フレームをスタックにプッシュします。
つまり、上記のコードサンプルの場合
状態切り替えの実行トレース
- ソースの状態=記録
-
ターゲット状態= alsoStreamToRemoteIp
-
ソースからの降下= recording-> root(trace = [root])
-
ターゲットからの降下= alsoStreamToRemoteIp-> playback-> root(trace = [playback、root])
-
ルートで交差します。
記録からalsoStreamToRemoteIpに切り替えるには、
- ポップ"録音"スタックから(およびその終了関数を呼び出します...ここでは定義されていません)。
- プッシュ"再生"スタックに追加します(そして、Enter関数を呼び出します)。
- プッシュ" alsoStreamToRemoteIp"スタックに追加します(そしてEnter関数を呼び出します)。
解決
2つのこと:
1:ほとんどの場合、プログラムの状態をモデルとして表現し、直接またはMVCパターンを介してプログラムと対話します。
2:本当にFSMが必要な場合、つまり、モデルに対して一連のアクションをランダムに行いたい場合、特定の時間に許可されるのはその一部のみです。その後......
プログラムの状態をモデル(または分解と複雑さに応じて複数のモデル)に保持し、状態と遷移を表します。
class State:
def __init__(self):
self.neighbors = {}
隣人が {Action:State}
の辞書を含む場合、次のようなことができます
someAction.execute() # Actions manipulate the model (use classes or lambdas)
currentState = currentState.neighbors[someAction]
さらにクールなのは、無限ループを使用して、近隣からアクションをランダムに選択し、実行し、状態を無期限に移動することです。プログラムをテストするのに最適な方法です。
他のヒント
ここですべての詳細を確認するかどうかはわかりません。ただし、複数のステートマシンがあるFSM(有限状態マシン)の実装を説明しているようです。場合によっては、FSM F1の特定の状態(S1)で特定のイベント(E1)が発生すると、全体の処理を簡素化するために新しいFSMを入力する必要があります(F2と呼びます)。
その場合、S1でE1が発生すると、イベント読み取りを引き継いでF2 FSMを実装するアクションルーチンを呼び出す必要があります。呼び出されると、F2の開始状態で処理を開始し、関連するサブイベントを処理します。終了状態に達すると、F2のインタープリターは終了します。 F2の実行中に中断されたF1アクションルーチンに情報を返すことがあり、F1の次の状態がその影響を受ける可能性があります。
説明の残りの部分(「ブロックのオーバーライド」など)は、実装にアクセスできない人にはあまり意味がありません。