C++有限状态机实现详解

目录
  • 有限状态机四大要素
  • C++函数指针实现
  • 总结

前提:因为最近打算学设计模式的状态模式,但不是很明白有限状态机和状态模式之间的关系,索性用C++实现了一个简单案例复习了一下FSM,如果有更好的实现方法,欢迎留言

有限状态机四大要素

  • 现态:当前所处状态
  • 次态:当条件满足后,即将转移的下一个状态
  • 动作:当满足某个事件时执行的动作;动作执行完毕后可以转移到另一个状态或保持原有状态
  • 条件:转移状态所需的条件,当满足条件时,会触发一个动作或进行状态转移

C++函数指针实现

案例:学生的日常生活。

  • 学生的日常生活包含以下几个状态:起床、上学、吃午饭、做作业、睡觉;
  • 每个状态之间进行转移需要执行相应的事件。

我分为以下几个步骤来实现:

  • (1)绘制状态转移图
  • (2)创建状态转移的FSMItem类
    • 枚举:所有状态State、所有事件Event;
    • 成员变量:现态_curState、事件_event、次态_nextState
    • 成员函数:动作函数
  • (3)创建有限状态机FSM类
    • 成员变量:状态转移表vector<FSMItem*> _fsmTable
    • 成员函数:初始化状态转移表、状态转移、根据事件执行相应动作
  • (4)测试FSM

(1)绘制状态转移图

(2)FSMItem类

//FSM状态项
class FSMItem
{
    friend class FSM;
private:
   	//动作函数
    static void getUp()
    {
        cout << "student is getting up!" << endl;
    }
    static void go2School()
    {
        cout << "student is going to school!" << endl;
    }
    static void haveLunch()
    {
        cout << "student is having lunch!" << endl;
    }
    static void doHomework()
    {
        cout << "student is doing homework!" << endl;
    }
    static void sleeping()
    {
        cout << "student is sleeping!" << endl;
    }
public:
    //枚举所有状态
    enum State
    {
        GETUP = 0,
        GOTOSCHOOL,
        HAVELUNCH,
        DOHOMEWORK,
        SLEEP
    };
    //枚举所有事件
    enum Events
    {
        EVENT1 = 0,
        EVENT2,
        EVENT3
    };
public:
    //初始化构造函数
    FSMItem(State curState, Events event, void(*action)(), State nextState)
        :_curState(curState), _event(event), _action(action), _nextState(nextState) {}
private:
    State   _curState;      //现态
    Events  _event;         //条件
    void    (*_action)();   //动作
    State   _nextState;     //次态
};

(3)FSM类

class FSM
{
public:
    //初始化状态机
    FSM(FSMItem::State curState= FSMItem::GETUP):_curState(curState)
    {
        initFSMTable();
    }
    //状态转移
    void transferState(FSMItem::State nextState)
    {
        _curState = nextState;
    }
    //根据当前状态和发生的事件,执行相应的动作,并进行状态转移
    void handleEvent(FSMItem::Events event)
    {
        FSMItem::State  curState = _curState;   //现态
        void (*action)() = nullptr;//动作
        FSMItem::State nextState;  //次态
        bool flag = false;
        for (int i = 0; i < _fsmTable.size(); i++)
        {
            if (event == _fsmTable[i]->_event && curState == _fsmTable[i]->_curState)
            {
                flag = true;
                action = _fsmTable[i]->_action;
                nextState = _fsmTable[i]->_nextState;
                break;
            }
        }
        //找到对应的状态项,执行动作,转移状态
        if (flag)
        {
            if (action)
            {
                action();
            }
            transferState(nextState);
        }
    }
private:
    //根据画的状态转移图初始化状态转移表
    void initFSMTable()
    {
        _fsmTable.push_back(new FSMItem(FSMItem::GETUP, FSMItem::EVENT1, &FSMItem::getUp, FSMItem::GOTOSCHOOL));
        _fsmTable.push_back(new FSMItem(FSMItem::GOTOSCHOOL, FSMItem::EVENT2, &FSMItem::go2School, FSMItem::HAVELUNCH));
        _fsmTable.push_back(new FSMItem(FSMItem::HAVELUNCH, FSMItem::EVENT3, &FSMItem::haveLunch, FSMItem::DOHOMEWORK));
        _fsmTable.push_back(new FSMItem(FSMItem::DOHOMEWORK, FSMItem::EVENT1, &FSMItem::doHomework, FSMItem::SLEEP));
        _fsmTable.push_back(new FSMItem(FSMItem::SLEEP, FSMItem::EVENT2, &FSMItem::sleeping, FSMItem::GETUP));
    }
public:
    FSMItem::State _curState;  //现态
private:
    vector<FSMItem*> _fsmTable;  //状态转移表
};

(4)测试FSM

#include<iostream>
#include<vector>
using namespace std;
//测试事件变换
void testEvent(FSMItem::Events& event)
{
    switch (event)
    {
    case FSMItem::EVENT1:
        event = FSMItem::EVENT2;
        break;
    case FSMItem::EVENT2:
        event = FSMItem::EVENT3;
        break;
    case FSMItem::EVENT3:
        event = FSMItem::EVENT1;
        break;
    }
}
int main()
{
    FSM *fsm = new FSM();
    auto event = FSMItem::EVENT1;
    while (1)
    {
        cout << "event " << event << " is coming..." << endl;
        fsm->handleEvent(event);
        cout << "fsm current state is " << fsm->_curState << endl;
        testEvent(event);
    }
    return 0;
}

执行效果:

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • StateMachine 状态机机制深入解析

    前言 Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程. 之前,我们使用二维数组实现状态机机制,现在,我们来用 Spring StateMachine 进行改造. 环境依赖 修改 POM 文件,添加 spring-statemachine-core 依赖. <dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>

  • C语言中的状态机设计深入讲解

    前言 本文不是关于软件状态机的最佳设计分解实践的教程.我将重点关注状态机代码和简单的示例,这些示例具有足够的复杂性,以便于理解特性和用法. 背景 大多数程序员常用的设计技术是有限状态机(FSM).设计人员使用此编程结构将复杂的问题分解为可管理的状态和状态转换.有无数种实现状态机的方法. A switch语句提供了状态机最容易实现和最常见的版本之一.在这里,每个案例在switch语句成为一个状态,实现如下所示: switch (currentState) { case ST_IDLE: // do

  • C++有限状态机实现计算器小程序

    本文介绍利用有限状态机原理开发计算器小程序的过程. 实现的功能 支持整数.小数输入 支持+ - * / 四则运算 CE 清除当前操作数 C 清除所有.回到初始状态 回显操作数和结果 HSM状态图 计算器可以分为七种状态:Start.Operand_1.Negate_1.Operator.Operand_2.Negate_2.Error.其中Start.Operand_1.Operand_1状态又分了几种子状态. 下面简要的介绍下状态状态转换的过程: 启动软件,进入Start状态 当用户点击1-9

  • javascript与有限状态机详解

    简单说,它有三个特征: 复制代码 代码如下: * 状态总数(state)是有限的.* 任一时刻,只处在一种状态之中.* 某种条件下,会从一种状态转变(transition)到另一种状态. 它对JavaScript的意义在于,很多对象可以写成有限状态机. 举例来说,网页上有一个菜单元素.鼠标悬停的时候,菜单显示:鼠标移开的时候,菜单隐藏.如果使用有限状态机描述,就是这个菜单只有两种状态(显示和隐藏),鼠标会引发状态转变. 代码可以写成下面这样: 复制代码 代码如下: var menu = { //

  • JS前端实现fsm有限状态机实例详解

    目录 引言 举个栗子 从零开始 获取状态 状态改变 transition 实现fsm状态机 实现钩子函数 完整代码 总结 引言 我们平时开发时本质上就时对应用程序的各种状态进行切换并作出相应处理,最直接的方法就是添加标志位然后考虑所有可能出现的边界问题,通过if...else if...else 来对当前状态进行判断从而达成页面的交互效果, 但随着业务需求的增加各种状态也会随之增多,我们就不得不再次修改if...else代码或者增加对应的判断,最终使得程序的可读性.扩展性.维护性变得很麻烦 有限

  • C++有限状态机实现详解

    目录 有限状态机四大要素 C++函数指针实现 总结 前提:因为最近打算学设计模式的状态模式,但不是很明白有限状态机和状态模式之间的关系,索性用C++实现了一个简单案例复习了一下FSM,如果有更好的实现方法,欢迎留言 有限状态机四大要素 现态:当前所处状态 次态:当条件满足后,即将转移的下一个状态 动作:当满足某个事件时执行的动作:动作执行完毕后可以转移到另一个状态或保持原有状态 条件:转移状态所需的条件,当满足条件时,会触发一个动作或进行状态转移 C++函数指针实现 案例:学生的日常生活. 学生

  • Python3爬虫中关于中文分词的详解

    原理 中文分词,即 Chinese Word Segmentation,即将一个汉字序列进行切分,得到一个个单独的词.表面上看,分词其实就是那么回事,但分词效果好不好对信息检索.实验结果还是有很大影响的,同时分词的背后其实是涉及各种各样的算法的. 中文分词与英文分词有很大的不同,对英文而言,一个单词就是一个词,而汉语是以字为基本的书写单位,词语之间没有明显的区分标记,需要人为切分.根据其特点,可以把分词算法分为四大类: ·基于规则的分词方法 ·基于统计的分词方法 ·基于语义的分词方法 ·基于理解

  • Android mvvm之LiveData原理案例详解

    1. 生命周期感知 1.1 生命周期感知组件 我们知道,Controller(Activity or Fragment) 都是有生命周期的,但是传统的 Controller 实现方式只负责 Controller 本身的生命周期管理,而与业务层的数据之间并没有实现良好解耦的生命周期事件交换.所以业务层都需要自己主动去感知 Controller 生命周期的变化,并在 Controller 的生存期处理数据的保活,而在消亡时刻解除与 Controller 之间的关系,这种处理方式随着业务规模的扩大往往

  • 微服务架构之服务注册与发现功能详解

    目录 微服务的注册与发现 1.服务注册 2.服务发现 3.注册中心 4.现下的主流注册中心 4.1 Eureka 4.1.1 介绍 4.1.2 整体架构 4.1.3 接入Spring Cloud 4.2 ZooKeeper 4.2.1 介绍 4.2.2 整体架构 4.2.3 接入Dubbo生态 4.3 Consul 4.3.1 介绍 4.3.2 整体架构 4.3.3 生态对接 4.4 总结对比 详解微服务架构及其演进史 微服务全景架构全面瓦解 微服务架构拆分策略详解 微服务的注册与发现 我们前面

  • AngularJS 日期格式化详解

    AngularJS是为了克服HTML在构建应用上的不足而设计的.HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了.所以我做了一些工作(你也可以觉得是小花招)来让浏览器做我想要的事. AngularJS的日期格式化有两种形式,一种是在HTML页面,一种是在JS代码里,都是用到AngularJS的过滤器$filter. HTML: date_expression 即 你在$scope中设的date类型变量(注意,一定是date object才正确), 也是要显

  • spring boot的maven配置依赖详解

    本文介绍了spring boot的maven配置依赖详解,分享给大家,具体如下: 我们通过引用spring-boot-starter-parent,添加spring-boot-starter-web 可以实现web项目的功能,当然不使用spring-boot-start-web,通过自己添加的依赖包也可以实现,但是需要一个个添加,费时费力,而且可能产生版本依赖冲突.我们来看下springboot的依赖配置: 利用pom的继承,一处声明,处处使用.在最顶级的spring-boot-dependen

  • 基于ES6作用域和解构赋值详解

    ES6 强制开启严格模式 作用域 •var 声明局部变量,for/if花括号中定义的变量在花括号外也可访问 •let 声明的变量为块作用域,变量不可重复定义 •const 声明常量,块作用域,声明时必须赋值,不可修改 // const声明的k指向一个对象,k本身不可变,但对象可变 function test() { const k={ a:1 } k.b=3; console.log(k); } test()解构赋值 { let a, b, 3, rest; [a, b, c=3]=[1, 2]

  • [译]ASP.NET Core 2.0 路由引擎详解

    本文介绍了ASP.NET Core 2.0 路由引擎详解,分享给大家,具体如下: 问题 ASP.NET Core 2.0的路由引擎是如何工作的? 答案 创建一个空项目,为Startup类添加MVC服务和请求中间件: public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvir

  • Asp.net MVC scheduler的实现方法详解

    Asp.net MVC scheduler的实现方法详解 本例使用了fullcalendar js : https://fullcalendar.io/ 1. view : @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } @section PageContent{ <style> .modal-backdrop { z-index: 9; } </sty

随机推荐