本文字数:4593字
预计阅读时间:14分钟
序章
什么是状态机?
我们还是直接使用wikiPedia上的定义:
❝A finite-state machine (FSM) or finite-state automaton (FSA, plural: automata), finite automaton, or simply a state machine, is a mathematical model of computation.
简言之:我们通常称作的状态机是有限状态机的简称,它是一种数学计算模型。
有限状态机(也就是有限自动机)如果进行一个分类的话,分类如下:
这张图只是看一个大概的分类,实际上这个有一个简单的认知就可以了,因为我们要探讨的种类主要就是DFA(Deterministic Finite Automaton):确定性有限状态自动机。它也是最简单的一种状态机模型,下文中我们简称为状态机的都是确定性有限状态自动机。
❝注:分类本身是有各种分类方式的,这里采取是以是否有输出作为分类的前提,Wikipedia上的分类方式和此种分类不太一致,大家可以参考对比一下。
那么确定性有限状态自动机有哪些特点呢?简单来讲就是每一种输入引起状态的变化是确定的,即一个状态对于同样的输入,只能有一种转换规则。
从一个简易的状态机模型开始
很多人每天上班都要刷卡进出地铁,我们就以有旋转栅门的地铁站闸机入口作为例子。
这个闸机口在开始的时候有一个“locked”的状态, 在这个状态下它并不会让乘客旋转栅栏通过进站口。当有人刷卡了,那么这个闸机口的状态就会变为“unlocked”,但是它并不会自己转动,必须得等到有人推动旋转栅栏通过闸机口,且在这之后闸机口的状态会再次变为“locked”。
从上面的描述中可以看到这个闸机口总是处于两种状态之一:Locked 或者 Unlocked。同时也只有两种转化的触发条件:刷卡 或者 通过旋转栅栏。
接下来,我们可以通过图形的方式来给这个闸机系统建模,使用圆角矩形代表状态,使用箭头代表状态之间的转换:
上述系统大概描述出了该系统是如何工作的,但是还有一些场景是这个系统无法明确定义的。比如刷了卡之后马上又刷了一次卡,那么状态如何转变呢?比如还没有刷卡之前就有人要通过旋转栏,那么状态是如何转变呢?在上述的两种情况,我们建的状态机模型会保留在它的当前状态。
同时我们还得给这个系统加上一个初始的状态,这样我们就可以继续完善这个模型了:
有限状态机的定义
上述模型就是一个简单的状态机模型,基于此,我们可以从中总结出这个系统几个关键的特征:
这个系统包含有限的几个状态
这个系统包含有限的几个输入(或者事件)可以触发状态之间的转移
这个系统有一个特定的初始状态
这个系统在某一时刻的行为取决于当前的状态以及当前的输入
对于系统可能处于的每一个状态,每一个输入(或者事件)都会有对于的行为
❝• The system must be describable by a finite set of states.
• The system must have a finite set of inputs and/or events that can trigger transitions between states.
• The system has a particular initial state
• The behavior of the system at a given point in time depends upon the current state and the input or event that occur at that time.
• For each state the system may be in, behavior is defined for each possible input or event.
这个时候我们的定义已经够多了,有些理论,但是还是还不够,作为工程师,我们通常需要使用更加正式的,或者说更数学的方式来描述该系统,一个有限自动机M通常被五元组(Σ, Q, q0, F, δ)所定义:
Σ is the set of symbols representing input to M
Q is the set of states of M
q0 ∈ Q is the start state of M
F ⊆ Q is the set of final states of M
δ : Q × Σ → Q is the transition function
简单来说,该五元组为(输入,状态集,初始状态,结果状态集,转换方法), 那么这里的转换方法如何理解呢?它的参数就是当前状态 以及 输入 输出就是 结果状态 即 δ(q, x) = p。一个有限状态机 M 处于状态 q 中,接受到 x 输入,在处理完转换过程中的Action之后,就会变为状态 p 。
而对于这个转化方法的抽象,在我们自定义状态机的时候将尤为重要。
中章
实现状态机最简单的方法是使用枚举类和swtich-case语句来实现,但是我们今天不会使用这种方式,而是会尝试用两种不同的方式来定义一个状态机。
如何实现状态机 - 面向对象(OOP)
基本抽象
第一种方式是使用OOP的思路来完成一个通用的状态机,那么首当其冲的要考虑可以抽象出哪些类呢?结合上方的五元组,抽象如下:
protocol Event: Hashable { }
class State<E: Event> {
}
class StateMachine<E: Event> {
}
第一是事件:因为状态的转移是需要事件触发的,所以事件集在这里定义为一个Event协议,后面谁使用,谁定义相应的事件枚举即可。
第二是状态:这里把五元组中的Transition Function封装进状态类,直接由状态类本身来管理转换行为。
第三是状态机:这个就类似我们MVC中的view controller,是状态机的中枢,需要由它来管理状态的切换。
以上就是我定义的状态机模型的基建了,那么我们整体的设计思路呢?