私はいくつかの一般的なものを探しています
- 最適化
- 正しさ
- 拡張性
現在の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
ソースからの降順=記録->ルート(トレース= [ルート])
ターゲットからの降順=alsoStreamToRemoteIp->playingback-> root(trace = [playback、root])
ルートで交差します。
記録からalsoStreamToRemoteIpに切り替えるには、
- スタックから「記録」をポップします(そしてその終了関数を呼び出します...ここでは定義されていません)。
- 「再生」をスタックにプッシュします(そしてenter関数を呼び出します)。
- 「alsoStreamToRemoteIp」をスタックにプッシュします(そしてenter関数を呼び出します)。