如何在Swift中实现状态机?

本文介绍了如何在Swift中实现状态机,从理论定义到面向对象和函数式的实现方法。文章通过地铁闸机的例子展示了状态机的基本概念,并讨论了状态机的五元组定义。在面向对象实现中,定义了事件、状态和状态机类。而在函数式实现中,通过Transition和State Machine结构体实现了状态转换。最后,文章给出了实际应用案例和相关资源链接。
摘要由CSDN通过智能技术生成

47c105ee84db01b1c57a020c3050770a.png

 d6c10ff9869d749d26e11d949880db21.gif 

本文字数: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.

简言之:我们通常称作的状态机是有限状态机的简称,它是一种数学计算模型。

有限状态机(也就是有限自动机)如果进行一个分类的话,分类如下:

5fa77ae3ac6428368867993f48411e87.png

这张图只是看一个大概的分类,实际上这个有一个简单的认知就可以了,因为我们要探讨的种类主要就是DFA(Deterministic Finite Automaton):确定性有限状态自动机。它也是最简单的一种状态机模型,下文中我们简称为状态机的都是确定性有限状态自动机。

注:分类本身是有各种分类方式的,这里采取是以是否有输出作为分类的前提,Wikipedia上的分类方式和此种分类不太一致,大家可以参考对比一下。

那么确定性有限状态自动机有哪些特点呢?简单来讲就是每一种输入引起状态的变化是确定的,即一个状态对于同样的输入,只能有一种转换规则。

从一个简易的状态机模型开始

很多人每天上班都要刷卡进出地铁,我们就以有旋转栅门的地铁站闸机入口作为例子。

这个闸机口在开始的时候有一个“locked”的状态, 在这个状态下它并不会让乘客旋转栅栏通过进站口。当有人刷卡了,那么这个闸机口的状态就会变为“unlocked”,但是它并不会自己转动,必须得等到有人推动旋转栅栏通过闸机口,且在这之后闸机口的状态会再次变为“locked”。

从上面的描述中可以看到这个闸机口总是处于两种状态之一:Locked 或者 Unlocked。同时也只有两种转化的触发条件:刷卡 或者 通过旋转栅栏。

接下来,我们可以通过图形的方式来给这个闸机系统建模,使用圆角矩形代表状态,使用箭头代表状态之间的转换:

56a7ebfab814b9d01d8cd01cf15d810a.png

上述系统大概描述出了该系统是如何工作的,但是还有一些场景是这个系统无法明确定义的。比如刷了卡之后马上又刷了一次卡,那么状态如何转变呢?比如还没有刷卡之前就有人要通过旋转栏,那么状态是如何转变呢?在上述的两种情况,我们建的状态机模型会保留在它的当前状态。

同时我们还得给这个系统加上一个初始的状态,这样我们就可以继续完善这个模型了:

567513c16c81e0ac0c657eb7c30e835f.png

有限状态机的定义

上述模型就是一个简单的状态机模型,基于此,我们可以从中总结出这个系统几个关键的特征:

  • 这个系统包含有限的几个状态

  • 这个系统包含有限的几个输入(或者事件)可以触发状态之间的转移

  • 这个系统有一个特定的初始状态

  • 这个系统在某一时刻的行为取决于当前的状态以及当前的输入

  • 对于系统可能处于的每一个状态,每一个输入(或者事件)都会有对于的行为


• 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,是状态机的中枢,需要由它来管理状态的切换。

以上就是我定义的状态机模型的基建了,那么我们整体的设计思路呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值