源码路径:https://github.com/Ylttx/dll_fsm
项目应用层涉及了复杂的状态管理,原本使用基于函数指针的方式实现的有限状态机,经过了很多人很多次的功能添加、修改,变得异常庞大、难以维护。现在使用设计模式里的状态模式重构应用层代码。
重构思路借鉴了《设计模式:可复用面向对象软件的基础》的思想。
hsm/
├── Factory.h # 状态工厂
├── Machine.cpp
├── Machine.h # 使用状态机的机器类
├── MonitorState.cpp
├── MonitorState.h # 具体的状态类 继承状态基类
└── hsm_core # 层次状态机核心代码
├── Context.cpp
├── Context.h # 状态机上下文,管理多个状态
├── Input.h # 输入事件类
├── State.cpp
└── State.h # 状态基类
main.cpp # 测试代码
$ mkdir build && cd build && cmake .. && make
$ ./hsm
enter stopped state
Please input: 1 - Start, 2 - Stop.
1
T1: recieve start input.
exit stopped state
enter starting state
T2: check running
exit starting state
enter running state
T4: check error
exit running state
enter stopping state
T5: stop done
exit stopping state
1、状态类 dll_fsm/hsm/hsm_core/State.h
#ifndef STATE_H
#define STATE_H
#include "Input.h"
#include "Context.h"
#include
#include
namespace app {
class Machine;
}
namespace hsm {
class State {
friend class Context;
using FuncType = std::function;
public:
State();
virtual ~State() {}
virtual void enter(void);
virtual void exit(void) {}
virtual void update(void) {}
protected:
void setContext(Context *context);
void setMachine(app::Machine *machine);
void setInputHandle(FuncType func);
int sendSyncInput(const Input &input);
void transfer(int state);
bool isTimeOut(int64_t timeout);
app::Machine *m_machine;
private:
FuncType m_func;
Context *m_context;
std::chrono::steady_clock::time_point m_start;
};
} // namespace hsm
#endif
2、状态类 dll_fsm/hsm/hsm_core/State.cpp
#include "State.h"
namespace hsm {
State::State() : m_func(nullptr), m_context(nullptr) {}
void State::enter(void) {
m_start = std::chrono::steady_clock::now();
}
void State::setContext(Context *context) {
m_context = context;
}
void State::setMachine(app::Machine *machine) {
m_machine = machine;
}
void State::setInputHandle(FuncType func) {
m_func = func;
}
int State::sendSyncInput(const Input &input) {
if (m_func) {
return m_func(input);
}
return 0;
}
void State::transfer(int state) {
if (m_context) {
m_context->transferState(state);
}
}
bool State::isTimeOut(int64_t timeout) {
auto seconds = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_start);
return seconds.count() >= timeout;
}
} // namespace hsm
3、上下文类:dll_fsm/hsm/hsm_core/Context.h
#ifndef CONTEXT_H
#define CONTEXT_H
#include
#include "Input.h"
namespace app {
class Machine;
}
namespace hsm {
class State;
struct NodeState {
NodeState(State *state = nullptr) : m_state(state) {}
NodeState &operator=(const NodeState &rhs) {
m_state = rhs.m_state;
return *this;
}
State *m_state;
};
class Context {
public:
Context() {}
~Context();
State *createState(State *p_state, int state, app::Machine *machine);
void start(int state);
void update(void);
void transferState(int state);
void sendSyncInput(const Input &input);
int getCurrentState(void);
private:
std::unordered_map m_states;
NodeState m_cur_ns;
int m_cur_state;
};
} // namespace hsm
#endif
4、上下文类:dll_fsm/hsm/hsm_core/Context.cpp
#include "Context.h"
#include "State.h"
#include
namespace hsm {
Context::~Context() {
if (m_cur_ns.m_state) {
m_cur_ns.m_state->exit();
}
for (auto item : m_states) {
if (item.second.m_state) {
delete item.second.m_state;
item.second.m_state = nullptr;
}
}
m_states.clear();
}
State *Context::createState(State *p_state, int state, app::Machine *machine) {
if (!p_state || !machine) {
return nullptr;
}
p_state->setContext(this);
p_state->setMachine(machine);
NodeState ns(p_state);
m_states[state] = ns;
return p_state;
}
void Context::start(int state) {
auto it = m_states.find(state);
assert(it != m_states.end() && it->second.m_state != nullptr);
m_cur_state = state;
m_cur_ns = it->second;
m_cur_ns.m_state->enter();
}
void Context::update(void) {
m_cur_ns.m_state->update();
}
void Context::transferState(int state) {
auto it = m_states.find(state);
if (it != m_states.end()) {
m_cur_ns.m_state->exit();
m_cur_ns = it->second;
m_cur_ns.m_state->enter();
}
}
void Context::sendSyncInput(const Input &input) {
m_cur_ns.m_state->sendSyncInput(input);
}
int Context::getCurrentState(void) {
return m_cur_state;
}
} // namespace hsm
5、输入类:dll_fsm/hsm/hsm_core/Input.h
#ifndef INPUT_H
#define INPUT_H
namespace hsm {
class Input {
public:
Input(int type, void *p_data = nullptr) {
m_type = type;
m_data = p_data;
}
~Input() {}
int getType(void) const { return m_type; }
private:
int m_type;
void *m_data;
};
} // namespace hsm
#endif
以上是层次状态机的核心代码,使用代码参考文章开头处的github。