C++状态机设计

参考

一文了解状态机思路

使用C++设计模式优化状态机的实现

C++常见设计模式

状态转换表

OpenFSM 用法介绍

状态机要素

  • 状态:状态的数据和含义。

  • 事件:触发状态转换的条件,即从一个状态转移到另一个状态所需的条件。

  • 动作:每个状态下需要执行的动作操作。

状态机设计模型

  • 分支逻辑法

用 switch 描述状态转移,用 if-else 判断状态转移条件,用函数指针指定状态执行的动作。

这是状态机的简单实现方式,但是当业务需求持续增加,这样的状态机模型的维护成本也大大提高。

  • 表驱动法

用数据结构来存储状态及其对应的转换条件和动作。通过查表根据当前状态和输入事件找到下一个状态和动作。

事件A

事件B

事件C

事件D

状态A

\

To状态B \ 动作B

To状态C \ 动作C

\

状态B

\\

To状态C \ 动作C

To状态D \ 动作D

状态C

To状态A \ 动作A

\\

To状态D \ 动作D

状态D

To状态A \ 动作A

To状态B \ 动作B

\\

  • 状态模式

使用面向对象的方式,将状态抽象为类,每个状态类实现自己的行为和状态迁移逻辑。

class StateMachine;

/**
 * 状态基类,描述状态的共性
 */
class State {
 protected:
  StateMachine *machine_;
  
 public:
  virtual ~State() {}
  
  void SetMachine(StateMachine *machine) {
    machine_ = machine;
  }
  
  virtual void Run() = 0;
 
 private:
  virtual State* NextState() = 0;
};

/**
 * 状态派生类,描述状态具体动作
 */
class StateA : public State {
 public:
  void Run() override {
    std::cout << "StateA run." << std::endl; // 状态动作
    auto next_state = NextState(); // 事件判断
    if (next_state != nullptr)
      machine_->TransitTo(next_state); // 状态转移
  }
 
 private:
  State* NextState() {
    std::cout << "Next state: StateB" << std::endl; 
    return new StateB;
  }
};

class StateB : public State {
 public:
  void Run() override {
    std::cout << "StateB run." << std::endl; // 状态动作
    auto next_state = NextState(); // 事件判断
    if (next_state != nullptr)
      machine_->TransitTo(next_state); // 状态转移
  }
  
 private:
  State* NextState() {
    std::cout << "Next state: StateA" << std::endl; 
    return new StateA;
  }
};



/**
 * 状态机,状态机除了负责状态转移,还存储了各种状态共用的数据,以提供给状态作条件判断。
 */
class StateMachine {
 private:
  State *current_state_;
 
 public:
  StateMachine(State *state) : state_(nullptr) {
    TransitTo(state);
  }
  
  ~StateMachine() {
    delete current_state_;
  }

  void TransitTo(State *state) {
    if (current_state_ != nullptr) {
      delete current_state_;
    }
    current_state_ = state;
    current_state_->SetMachine(this);
  }

  void Run() {
    current_state_->Run();
  }
};



int main(int argc, char** argv) {
  StateMachine machine = new StateMachine(StateA);
  machine->Run();
}

事件判断可以进一步被分为内部事件和外部事件。内部事件数据信息可以存储在具体状态类自身。外部事件数据信息需要存储在状态机类中,这类信息可能被多个状态类使用到。

之后在状态机业务开发和维护中,仅需要修改具体状态类和状态机类的相关外部事件数据。

开源状态机库

  • StateSmith:跨平台开源工具,用于生成状态机代码。生成的代码是可读的,没有依赖性,适合微控制器。

  • TinyFSM:轻量级有限状态机库,专为实现最佳性能和低内存占用而优化,特别适合实时操作系统环境,框架无法适应多线程开发。

在 TinyFSM 这个框架中,由状态机列表来共同执行任务。一个任务是可以由多个不同对象来共同协作完成。每个对象都是一个状态机,这些状态机组成了状态机列表。在派发事件给到状态机时候,状态机会完成事件动作处理和状态切换。

  • OpenFSM:OpenFSM 被描述为全网最好用的 C++ 有限状态机。

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值