状态机改变状态
State Machine Change State
我一直 运行 遇到同样的问题,即使浏览教程也无法解决。
我已经“设置”了我的状态机,但我无法在状态之间转换。
这是我的状态机:
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,这让我痛苦地擦洗我的头。
But when I implement it I can't access the StateMachine from A::handleInput()
嗯,这是 State Pattern 的一个众所周知的问题,没有提及如何使用封闭的 状态机 [=50] 来保持状态 classes =].
IMO,这是将 StateMachine
class 作为 Singleton.
实施的有效用例之一
这样它的实例就可以从任何 State
class 实现中访问。
正如我在这里所说的设计模式,State classes 可以在 Flyweight Pattern 的帮助下设计,因为它们他们通常是无国籍人。
我曾经将所有这些驱动到一个 c++ 模板框架中,它抽象了 State 和 State Machine 的接口(参见 link 下面)。
下面是一个简短的代码示例:
StateMachine.h
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);
}
};
StateA.h
#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
}
}
};
这里省略了od StateB
的定义,应该和StateA
一样。
参考文献:
- C++ Singleton Design Pattern
- State machine template class framework for C++
我看过 Sourcemaking 示例,对我来说,实施示例真的很糟糕;必须在每次状态更改时创建新实例:
https://sourcemaking.com/design_patterns/state/cpp/1
就我个人而言,作为使用 JK 触发器设计电子设备状态机的人,我会使用类似但语义不同的方法。状态机的复杂性涉及根据状态和输入执行的 action;通常在 C 中,您会使用大量 switch 语句和可能描述如何处理 current state
和 new input
又名 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
}
}
我一直 运行 遇到同样的问题,即使浏览教程也无法解决。 我已经“设置”了我的状态机,但我无法在状态之间转换。
这是我的状态机:
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,这让我痛苦地擦洗我的头。
But when I implement it I can't access the StateMachine from
A::handleInput()
嗯,这是 State Pattern 的一个众所周知的问题,没有提及如何使用封闭的 状态机 [=50] 来保持状态 classes =].
IMO,这是将 StateMachine
class 作为 Singleton.
实施的有效用例之一
这样它的实例就可以从任何 State
class 实现中访问。
正如我在这里所说的设计模式,State classes 可以在 Flyweight Pattern 的帮助下设计,因为它们他们通常是无国籍人。
我曾经将所有这些驱动到一个 c++ 模板框架中,它抽象了 State 和 State Machine 的接口(参见 link 下面)。
下面是一个简短的代码示例:
StateMachine.h
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);
}
};
StateA.h
#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
}
}
};
这里省略了od StateB
的定义,应该和StateA
一样。
参考文献:
- C++ Singleton Design Pattern
- State machine template class framework for C++
我看过 Sourcemaking 示例,对我来说,实施示例真的很糟糕;必须在每次状态更改时创建新实例: https://sourcemaking.com/design_patterns/state/cpp/1
就我个人而言,作为使用 JK 触发器设计电子设备状态机的人,我会使用类似但语义不同的方法。状态机的复杂性涉及根据状态和输入执行的 action;通常在 C 中,您会使用大量 switch 语句和可能描述如何处理 current state
和 new input
又名 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
}
}