9

ステート パターンを使用して、C# で階層ステート マシンを実装しようとしています。ガイドとして、この例を使用しています。ただし、この例では、階層状態に関する回答は提供されていません。残念ながら、他の場所で良い例を見つけることができないようです。私の最初の考えは、階層状態のネストされたクラスを作成することです。しかし、これはベストプラクティスと見なされますか、それともより良い解決策がありますか?

ごきげんよう!

アップデート:

上記の状態パターンを実装しようと、午後中ずっと座っていました。HSM は非常に単純なメディア プレーヤーに基づいています。

代替テキスト http://www.freeimagehosting.net/uploads/e8d2d6486a.jpg

私はそれをやったと思ったが、私が理解していないことが1つある。最初に私が書いたコード(申し訳ありませんが、かなりたくさんあります):

public class MediaPlayer
{
    public MediaPlayerStates state;

    public MediaPlayer(MediaPlayerStates state)
    {
        this.state = state;
    }

    public void OnButtonPressed()
    {
        state.OnButtonPressed(this);
    }

    public void DeviceBooted()
    { 
        state. ?????
    }

    //Other Functions
}

//The 3 initial states (Start, On, End) know only 2 events.
public abstract class MediaPlayerStates
{
    public abstract void OnButtonPressed(MediaPlayer player);
    public abstract void OffButtonPressed(MediaPlayer player);
}

//The very beginpoint of the state machine
public class Start : MediaPlayerStates
{
    //When hitting the onbutton, the state changes to the OnState state
    public override void OnButtonPressed(MediaPlayer player)
    {
        player.state = new OnState(player);
    }

    //No need to implement this one
    public override void OffButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }
}

//OnState implements the 2 events from the MediaPlayerStates abstract class.
public class OnState : MediaPlayerStates
{
    //When entered the OnState state, a new entrypoint is creaeted: the Start state
    public OnState(MediaPlayer player)
    {
        player.state = new OnStartState();
    }

    //The OnState doesn't have a OnButtonPressed event so it doesn't need to be implemented
    public override void OnButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }

    //When hitting the offbutton in the OnState, the new state is End
    public override void OffButtonPressed(MediaPlayer player)
    {
        player.state = new End();
    }

    //The OnState itself containts 3 events, therefore these need to be implemented by every state whitin the OnState state
    public abstract class SubStates : MediaPlayerStates
    {
        public abstract void DeviceBooted(MediaPlayer player);
        public abstract void PlayButtonPressed(MediaPlayer player);
        public abstract void StopButtonPressed(MediaPlayer player);
    }

    //The OnStartState is the pseudoState where the On state starts
    public class OnStartState : SubStates
    {
        //When booted, the state of the player changes to the ShowMediaFileState state
        public override void DeviceBooted(MediaPlayer player)
        {
            player.state = new ShowMediaFileState();
        }

        //The events below don't need to be implemented since they don't exist. 
        public override void PlayButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void StopButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OnButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OffButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }
    }

    public class ShowMediaFileState : SubStates
    {
        //This event doesn't exists for this state
        public override void DeviceBooted(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //When hitting the play button in this state, play the mediafile
        public override void PlayButtonPressed(MediaPlayer player)
        {
            player.state = new PlayMediaFileState();
        }

        //These events also don't exist for this state
        public override void StopButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OnButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OffButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }
    }

    public class PlayMediaFileState : SubStates
    {
        //This event doesn't exist for this state
        public override void DeviceBooted(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //This event doesn't exist for this state
        public override void PlayButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //While playing a file and hitting the stopbutton, the state changes to the ShowMediaFileState state
        public override void StopButtonPressed(MediaPlayer player)
        {
            player.state = new ShowMediaFileState();
        }

        //This event doesn't exist for this state
        public override void OnButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //This event doesn't exist for this state
        public override void OffButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }
    }
}

//The endstate doesn't need any implementation since there cannot occur a event while being off
public class End : MediaPlayerStates
{
    public override void OnButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }

    public override void OffButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }
}

MediaPlayer クラスでイベントを定義するとき、他の関数を呼び出すことができません

  • OnButtonPressed
  • OffButtonPressed

だから、私の実装は良いのでしょうか? なにが問題ですか?複合パターンを使用するという提案も見ようとしましたが、状態パターンでどのように使用する必要があるかわかりません。誰でも助けてくれることを願っています!

4

4 に答える 4

3

Composite も必要になると思います。これにより、ステート マシンを相互にリンクできるようになります。

于 2010-08-15T11:43:26.883 に答える
2

状態パターンを使用して HSM を作成するには、サブ状態を含む各状態がそれ自体が状態マシンである必要があります。このようにして、上位レベルはサブステートの知識を持たず (副作用が少なくなります)、状態はサブステートをより適切に管理できます (デフォルトの状態を持つことができ、最後の状態を記憶することができます)。

ところで、アクションで何も役に立たないときに例外をスローするのは間違っています。無視してください。例外的なケースでのみ例外をスローします。間違ったボタンを押すことは、ユーザーの予期される動作です。

于 2011-02-10T11:16:29.847 に答える
1

一般的な方法で機能させるには、ステート マシンの階層をツリー構造として扱う必要があります。ノード間の遷移では、ツリーの最小共通祖先 (LCA) アルゴリズムを使用してから、ソース ノード祖先の共通祖先の下のノードから終了し (出口を子ノードにカスケードします)、ターゲット ノード祖先の各ノードに入ります。最後に、ターゲット ノードに子ノードがある場合は、他の複合状態に入る場合と同じようにそれらを入力する必要があります。

これは、UML Superstructure Specification で言及されている方法です。

これは上記のメソッドを実装しているため、https://github.com/steelbreeze/state.csのソース コードを見てください。

実際の例を確認するには、姉妹 JavaScript バージョンのプロジェクト サイト ( http://www.steelbreeze.net/state.js/ ) を参照してください。

于 2013-06-08T08:31:42.850 に答える
1

独自の FSM フレームワークの実装を開始する前に、SMC (State Machine Compiler) を確認してください。

SMC は、ステート マシンのテキスト定義を取得し、それを実装するコードを生成します。C# を含む幅広い言語のバックエンドがあります。また、ドット ファイルを出力して FSM の図を生成することもできます。

SMC は、プッシュ遷移とポップ遷移を備えた階層ステート マシンに似たものを作成できます。基本的に、プッシュは制御を新しいステート マシンに転送し、ポップは制御を元のステート マシンに戻します。

于 2010-08-15T12:28:32.170 に答える