我曾经实现过这样的状态机:
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
的 s 和当前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
模板?当我不知道's 方法的名称或签名时,我能否以某种方式表示,每当调用 的方法时StateInterface
,StateMachine
它应该调用相同的方法 on ?currentState
StateInterface