3

私はかつて次のようなステートマシンを実装しました:

class Player
{
public:
    int Run();
    int Jump();
    int Stop();

private:
    class State
    {
    public:
        virtual int Run() = 0;
        virtual int Jump() = 0;
        virtual int Stop() = 0;
    };

    class StandingState : public State
    {
        virtual int Run() { /*...*/ }
        virtual int Jump() { /*...*/ }
        virtual int Stop() { /*...*/ }
    };

    class RunningState : public State
    {
        virtual int Run() { /*...*/ }
        virtual int Jump() { /*...*/ }
        virtual int Stop() { /*...*/ }
    };

    // More states go here!

    std::list<State*> states;
    State* currentState;
};

int Player::Run()
{
    int result = m_currentState->Run();

    // do something with result
}

int Player::Jump()
{
    int result = m_currentState->Jump();

    // do something with result
}

int Player::Stop()
{
    int result = m_currentState->Stop();

    // do something with result
}

Player外部からの呼び出しを現在のStateオブジェクトに委譲し、結果で何かを行います (別の状態に遷移する可能性があります) 。基本的に、各状態は特定のアクションがどのように影響するかを認識していますが、さまざまな状態を結び付けるのは状態マシン次第です。これは、懸念事項の適切な分離であることがわかりました。

しかし、ここで抽象化の可能性を見ています。システム全体は、Stateクラスのインターフェースによって定義されます。

  1. ステートマシンとサブステートの両方が実装されていますState
  2. ステート マシンは、可能なすべてStateの と現在のState
  3. ステート マシンでどのようなメソッドStateが呼び出されても、それは見分けがつかずに現在の状態に転送されます。

それで、これを完全にクラステンプレートにすることができますよね? 見て:

template< class StateInterface >
class StateMachine : public StateInterface
{
    // public methods already declared in StateInterface

protected:
    std::list<StateInterface*> states;
    void AddState(StateInterface* state);
    StateInterface* currentState;
};

class PlayerStateInterface
{
public:
    virtual int Run() = 0;
    virtual int Jump() = 0;
    virtual int Stop() = 0;
};

class Player : public StateMachine< PlayerStateInterface >
{
public:    
    virtual int Run() { currentState->Run(); /* do stuff */ }
    virtual int Jump() { currentState->Jump(); /* do stuff */ }
    virtual int Stop() { currentState->Stop(); /* do stuff */ }
};

上記のポイントのうち、1と2はカバーしていますが、3はどうですか?具体的なステート マシンの実装では、呼び出しを現在の状態に手動で委譲する必要があります。その機能をStateMachineテンプレートに移動する方法はありますか? のメソッドの名前またはシグネチャがわからない場合、のメソッドStateInterfaceが呼び出されるたびStateMachineに、 の同じメソッドを呼び出す必要があることをどうにかして表現できますか?currentStateStateInterface

4

1 に答える 1