我一直在遇到相同的问题,即使在阅读教程时也无法解决。 我已经“设置”了状态机,但无法在状态之间进行转换。
这是我的StateMachine:
class StateMachine
{
State* m_State;
public:
StateMachine();
~StateMachine();
void changeState(State* state);
};
这是一个示例状态:
class A : State
{
public:
A();
~A();
void handleInput(int a);
}
如果我将a = 1传递给A :: handleInput(),我想转换到状态B。但是当我实现它时,我无法从A :: handleInput()访问StateMachine,这使我在其中擦洗头痛苦。
答案 0 :(得分:0)
但是当我实现它时,我无法从
访问StateMachineA::handleInput()
好吧,这是State Pattern的一个众所周知的问题,没有提到如何使用封闭的 State Machine 来保持状态类的状态。
IMO,这是将StateMachine
类实现为Singleton的有效用例之一。
这样,就可以从任何State
类实现中访问其实例。
正如我在这里所说的设计模式一样, State 类可以借助Flyweight Pattern进行设计,因为它们本身通常是无状态的。
我曾经将所有这些驱动到一个c ++模板框架中,该框架抽象了 State 和 State Machine 的接口(请参见下面的链接)。
以下是通过这些方式编写的简短代码示例:
struct State {
virtual void handleInput(int x) = 0;
virtual ~State() {} = 0;
};
class StateMachine {
State* m_State;
StateMachine();
public:
static StateMachine& instance() {
static StateMachine theInstance;
return theInstance;
}
void changeState(State* state) {
m_State = state;
}
void triggerInput(int x) {
m_State->handleInput(x);
}
};
#include "StateMachine.h"
class StateB;
extern StateB* stateB;
class StateA : public State {
public:
virtual ~StateA() {}
virtual void handleInput(int x) {
if(x == 1) {
// Change to StateB
StateMachine::instance.changeState(stateB);
}
else {
// Do something with x
}
}
};
我在这里省略了StateB
的定义,应该与StateA
相同。
参考:
答案 1 :(得分:0)
我看了一个Sourcemaking示例,对我来说,实现示例确实很糟糕;必须在每次状态更改时创建新的实例: https://sourcemaking.com/design_patterns/state/cpp/1
我个人是使用JK触发器设计电子设备中的状态机的人,因此我会使用类似但语义上不同的方法。状态机的复杂性包括根据状态和输入执行的 action 。通常,在C语言中,您会使用很多switch语句以及可能描述了如何处理current state
和new input
aka event
的数组来完成此操作。
因此,对我而言,面向对象的方法是对event handler
进行建模。这将具有一个描述输入格式的接口。然后,对于每个不同的状态,您都有该接口的不同实现。这样,状态机可以简单地实现事件处理程序的状态集合-数组,向量或映射。尽管处理程序可能仍然包含case语句,但是总体上的意大利面程度已大大降低。您可以在必要时使用新的状态处理程序轻松扩展设计:
所以您可能会遇到这样的事情:
#include <map>
typedef enum
{
//TODO : state list, e.g.
eOff,
eOn
}
teCurrentState;
typedef struct
{
//TODO : Add inputs here, e.g.
bool switch1;
}
tsInputDesc;
typedef struct
{
//TODO : Add outputs here, e.g.
bool relay1;
}
tsOutputDesc;
// ------------------------------------------------
class IEventHandler
{
public:
virtual ~IEventHandler() {}
// returns new state
virtual teCurrentState handleInput(tsInputDesc const& input, tsOutputDesc& output) = 0;
};
// ------------------------------------------------
class OnStateHandler : public IEventHandler
{
public:
virtual teCurrentState handleInput(tsInputDesc const& input, tsOutputDesc& output) override
{
//TODO : IMPLEMENT
teCurrentState newState = TODO....
return (newState);
}
};
// ------------------------------------------------
class OffStateHandler : public IEventHandler
{
public:
virtual teCurrentState handleInput(tsInputDesc const& input, tsOutputDesc& output) override
{
//TODO : IMPLEMENT
teCurrentState newState = TODO....
return (newState);
}
};
// ------------------------------------------------
class StateMachine
{
protected:
teCurrentState mCurrentState;
std::map<teCurrentState, IEventHandler*> mStateHandlers;
void makeHandlers()
{
mStateHandlers[eOff] = new OffStateHandler();
mStateHandlers[eOn] = new OnStateHandler();
}
public:
StateMachine()
{
makeHandlers();
mCurrentState = eOff;
}
void handleInput(tsInputDesc const& input, tsOutputDesc output)
{
teCurrentState newState = mStateHandlers[mCurrentState]->handleInput(input, output);
mCurrentState = newState;
}
};
// ------------------------------------------------
void runFsm()
{
StateMachine fsm;
tsInputDesc input;
tsOutputDesc output;
bool alive = true;
while (alive)
{
// TODO : set input according to....inputs (e.g. read I/O port etc)
fsm.handleInput(input, output);
// TODO : use output
}
}