私はかつて次のようなステートマシンを実装しました:
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
クラスのインターフェースによって定義されます。
- ステートマシンとサブステートの両方が実装されています
State
- ステート マシンは、可能なすべて
State
の と現在のState
- ステート マシンでどのようなメソッド
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
に、 の同じメソッドを呼び出す必要があることをどうにかして表現できますか?currentState
StateInterface