有限状态机的C++实现

有限状态机的C++实现

  • 实现动机
  • 代码层次架构
  • 编译运行
  • 源码解析

实现动机

源码路径: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               # 测试代码

有限状态机的C++实现_第1张图片

编译运行

$ 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。

你可能感兴趣的:(C/C++,c++,状态模式)