目录
为什么要写这篇
关注了一些微信公众号,推送的文章中提到了一个概念:状态机,当时本着收藏,等到想看的时候再看的想法,就这么一点点积累,等到后来意识到这个概念相关文章已经攒了6篇,后来很少看到相关文章了,而这个概念还没学会,又了解到这个和设计模式有关,设计模式和面向对象编程息息相关。
收藏第一篇关于状态机的文章到开始写这篇博客,整整三个月了,想想都觉得自己的拖延症。。。
状态机粗浅认识
状态机是一个抽象的概念,因此通过代码表达出来形式多种多样,那怎么算是状态机,就像什么是链表,栈和队列一样。
状态机是有限状态自动机(FSM)的简称,是现实事物运行规则抽象而成的一个数学模型。
有限状态自动机FSM,有限状态,它的状态是有限的。自动,给定一个状态机,同时给定它的当前状态以及输入,那么输出状态是可以明确的运算出来的。可以理解到状态机相关的概念中肯定有两个概念:输入状态(当前状态),输出状态(下一个状态)。
到这儿为止感觉和编程还没有多大关联,只是觉得和逻辑门电路(与门,或门,非门等)有一些相似,
为什么和编程还没什么关系呢?程序 = 数据结构 + 算法。 状态机是个抽象的概念,链表也是个抽象的概念,链表需要用一种结构来表示,状态机也需要一种结构来表示,数据结构就有了。链表需要提供操作接口,主要的就是增 、删、改、查,初始化和清空。这些操作接口的实现方法就属于算法。状态机同样需要提供操作接口,操作接口的实现也属于算法呀。
对于单片机编程从某种层面来说可以粗略地理解为传感器采集发生了哪些事件,然后做了相应处理动作。
明白了这些大致就了解状态机是什么了。相关的概念就是四个:当前的状态(逻辑状态输入),发生的事件(单片机输入),执行的功能函数(单片机输出),下一个状态(逻辑状态输出)
我联想到“黑盒”和“模块化”:状态机是个黑盒,给它确定的输入,就会有对应的输出。状态机可以看作是个模块,与硬件关联不大,可以写成独立的模块文件,方便移植。
我认为状态机的作用是为了得到输出,输出有两个,执行功能函数 和 下一个状态,下一个状态 是主要矛盾,执行功能函数是次要矛盾,用C语言(或者是编程语言)相关术语来说,就是“副作用”
为什么给其确定的输入,就有对应的输出?通过查表,什么表?状态表。当前状态和发生的事件与 状态表中进行一一对比,查找到对应的则执行相应的功能函数和输出下一个状态。
为什么会有状态机
因为前人的经验总结
数字电路最重要的是逻辑,单片机编程和数字电路关联密切,单片机编程中最该重视的是逻辑,每个人都有自己的思维逻辑,对于复杂的逻辑如何保证自己写的代码可以让别人看懂呢?流程图?流程图大概是线性的,只是设计到的操作比较多,需要流程图一步步表示出来,但我不认为这是复杂的逻辑,什么是复杂的逻辑?面条代码?绕来绕去,让人理解起来一个头两个大,当然面条代码不可取。复杂的逻辑该是单以逻辑来说就比较复杂,比如多对多关系,用代码实现起来更加让人不知所云,为了让代码更容易理解,需要先直观地表示清楚,需要一张图,比如这样,操作系统的状态切换图, 这就是状态迁移图。然后。。。然后应该就有了状态机的概念。嗯嗯,应该是这样!
数学模型就有表示方法,状态机的表示方法是:状态迁移图 和 状态迁移表,状态迁移图可以用思维导图的方式画出来,状态迁移表就和数字电路上的真值表有些相似(将所有情况列举出来)。
关于状态机有什么用途
我的认识还比较浅,但还是知道有两三个和编程相关的应用。
-
操作系统的 进程管理
-
只是按键实现交互的全自动洗衣机
-
很多协议的开发需要用到状态机,比如自定义协议的解析用在蓝牙芯片上
-
正则表达式通过转换为非确定性有穷自动机来实现
-
多功能闹钟也可以通过状态机来处理其较复杂的逻辑
用了状态机有什么好处
逻辑清晰,以一种大家都了解的框架来处理程序使得复杂的逻辑对于同事来说代码可读性较高,易于协作
一个健壮的状态机可以让你的程序,不论发生何种突发事件都不会突然进入一个不可预知的程序分支。程序更健壮。
状态机好学会吗
初学者往往会把某个“程序动作”当作是一种“状态”来处理,可以称之为“伪态” 。如何区分“动作” 和 “状态”? 看二者的本质:“动作”是不稳定的,即使没有条件触发,“动作”一旦执行完毕就结束了。而状态是相对稳定的,没有外部条件触发,一个状态会一直持续下去。
初学者另一种比较致命的错误,就是在状态划分时漏掉一些状态,可以称之为“漏态” 。
“伪态”和“漏态”这两种错误的存在,会导致程序结构的涣散,因此要特别小心避免。
关于状态机实现方式
状态机可以是一级的,也可以是多级的,在实现前需要先了解一下有这么回事。
关于实现方式我还是比较喜欢结构体数组的方式,关于switch...case 或 if...else, 我感觉和状态机的四个概念对应起来比较勉强,如果是多级状态机的话,或者状态比较多的话会导致一个函数过于庞大,相当于状态机没有好好利用。
使用函数指针实现 FSM的过程是比较费时费力的,但是这一切相对一大堆的 if...else switch...case来说都是值得的。基于这种表结构的状态机,维护程序起来会清晰很多 。
关于一对一关系的拓展
数据结构大致包含以下几种存储结构:
-
线性表,可细分为顺序表,链表,栈和队列。具有一对一关系
-
树结构,包括普通数,二叉数。具有一对多关系
-
图存储结构。具有多对多关系
状态机相关文章列表
可以都看看,也可以都不看,看:看状态机是什么,不看:只要自己通过代码实现就不用看人家怎么写的了