状态机简单介绍
软件设计中的状态机概念,一般是指有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
FSM(有限状态机)可以使用UML中的状态机图来表示。也可以使用类似以下格式的状态转移表等等。下面展示最常见的表示:当前状态(B)和事件(Y)的组合指示出下一个状态(C)。
状态转移表 | |||
---|---|---|---|
当前状态 → 事件 ↓ | 状态 A | 状态 B | 状态 C |
事件 X | … | … | … |
事件 Y | … | 状态 C | … |
事件 Z | … | … | … |
状态机有两个很重要的概念: 状态、事件。以下是一个CD机的简单例子:
CD机状态转移表
状态 → 事件 ↓ | 播放 | 暂停 | 停止 |
---|---|---|---|
按播放键 | … | 播放 | 播放 |
按停止键 | 停止 | 停止 | … |
按暂停键 | 暂停 | … | … |
通过这个表,我们可以很直观的来理解状态机,如下:
-
简单的CD机一般有三种状态: 播放、暂停、停止
-
我们对CD机的操作,就是事件,简单来说有三种事件:按播放、停止、暂停按键。
-
在CD机不同的状态下,发生不同的事件(按不同的按钮),触发的事情以及CD机下一步的状态(即状态转移)是不一样的。
-
按照以上表格,假如CD机当前状态是“播放”,这时候,我们按播放键,它会保持“播放”状态,不会发生状态转移,如果按暂停键,则会触发状态转移,CD机状态转移为“暂停”状态。同理,按停止键会转移为停止状态。
状态机的实现方式
在软件的开发过程中,很多情况下,我们都会涉及到“状态”这个概念,比如监控服务器的软件,服务器会有:‘开机’,‘关机’,‘负载过高’等状态。
执行任务的软件,对于每个任务,会有“队列中”,“准备”,“运行”,“运行完毕”,“失败”等状态,任务在不同的状态下,发生不同的事件,状态迁移和对应的逻辑都是不一样的,比如在“队列中”状态,发生事件“取消任务”,这时候只需要把任务移出队列,并且状态变更为“失败”就行。同样,在“运行”状态时发生事件“取消任务”,则需要做很多工作,比如回收运行任务的资源等。
通常状况下,如果状态很少,可能不会涉及到状态机这个概念。但是如果状态、事件很多,如果设计不好状态机,软件开发到后期会非常吃力。对于后续的维护和升级也是问题。
状态机的实现无非就是 3 个要素:状态、事件、响应。
用 C 语言实现状态机主要有 2 种方法:switch—case 法、表格驱动法
switch—case 法
状态用 switch—case 组织起来, 将事件也用switch—case 组织起来, 然后让其中一个 switch—case 整体插入到另一个 switch—case 的每一个 case 项中 。
表格驱动法
如果说switch—case 法是线性的,那么表格驱动法则是平面的。表格驱动法的实质就是将状态和事件之间的关系固化到一张二维表格里, 把事件当做纵轴,把状态当做横轴,交点[Sn , Em]则是系统在 Sn 状态下对事件 Em 的响应 。
表格驱动法屏蔽了不同状态下处理各个事件的差异性,因此可以将处理过程中的共性部分提炼出来,做成标准统一的框架式代码,形成统一的调用接口。
表格驱动法查找目标实际上就是一次二维数组的寻址操作,所以它的平均效率要远高于switch—case 法。