状态机和状态图简介
状态图(statecharts)是一种图形语言,它用来描述过程中的状态。
你可能也用过类似的图,来设计用户流程图、规划数据库、或者构建 APP 架构。状态图(statecharts)是换种方式,用一堆盒子和箭头,来给人展示什么叫流程。不过,有了 XState,我们就能用代码来管理应用逻辑了。
这篇指南,会用初学者友好的方式,给你讲讲状态图(statecharts) 基础,内容如下:
- 状态 states
- 转换与事件 transitions and events
- 初始状态 initial states
- 最终状态 final states
- 复合状态 compound states
- 并行状态 parallel states
- 自转换 self-transitions
- 计划状态图 planning statecharts
- 延迟状态图 delayed transitions
- 动作 actions
状态 States
我们用圆角矩形盒子来展示 状态。为狗的过程,绘制状态图,首先会想到两种状态:
狗总是 睡着(asleep) 或 醒着(awake)。狗不能同时睡着和醒着,狗也不可能不睡不醒。只有这两种状态,没其它的了,这就是我们说的有限数量的状态。
转换与事件 Transitions and events
狗在 睡着 和 醒着 之间的变化,是通过转换来表示的,它用一个箭头表示,从一个状态指向过程序列中的下一个状态。
转换(transition)是由导致状态更改的 事件(event) 引起的。用事件来标记转换。
转换和事件是 确定性 的。 确定性意味着每个转换和事件总是指向相同的下一个状态,并且每次进程运行时总是从给定的起始条件产生相同的结果。 你永远不会把狗摇醒后,它还 睡着 ,或打晕它 它还 醒着 吧。
小狗具有两个有限状态,和两个转换的过程,就是一个 有限状态机。 状态机用于描述某事物的行为。 状态机描述事物的状态,以及这些状态之间的转换。 它是一个有限状态机,因为它具有有限数量的状态。(缩写为 FSM)
初始状态 Initial state
任何具有状态的事物,都会有一个 初始状态,即进程存在的默认状态,直到发生事件,从而改变事物的状态。
初始状态用实心圆圈表示,箭头从圆圈指向初始状态。
用状态图来描述遛狗的过程,初始状态会是 等待(waiting) 走路。
最终状态 Final state
大多数具有状态的进程都会有一个 最终状态,即进程完成时的最后一个状态。 最终状态由状态圆角矩形框上的双边框表示。
在遛狗状态图中,最终状态是 溜狗完成(walk complete)。
复合状态 Compound states
复合状态是可以包含更多状态的状态,也称为子状态。 这些子状态只能在父级复合状态发生时发生。在遛狗(on a walk)状态中,可以有 走路中(walking)、 奔跑中(running) 和 停下来闻闻好闻的气味(stopping to sniff good smells) 几个子状态。
复合状态由标记的圆角矩形框表示,该框充当其子状态的容器。
复合状态还应指定哪个子状态是初始状态。 在 on a walk 状态下,初始状态为 walking。
复合状态使状态图能够处理比日常状态机更复杂的情况。
原子状态 Atomic states
原子状态是没有任何子状态的状态。等待(Waiting), 遛狗完成(walk complete), 走路(walking), 奔跑(running) 和 停下来闻闻好闻的(stopping to sniff good smells) 都是原子状态。
并行状态 Parallel states
并行状态是一种复合状态,其中所有子状态(也称为区域)同时处于活动状态。 这些区域在复合状态容器内由虚线分隔。
在 on a walk 复合状态内,可能有两个区域。 一个区域包含狗的 walking、 running 和 stopping to sniff good smells 的活动子状态,另一个区域包含狗的尾巴 摇动(wagging) 和 不摇动(not wagging) 状态。 狗可以走路和摇尾巴,跑和摇尾巴,或者在摇尾巴的同时停下来闻,它也可以在不摇尾巴的情况下进行任何这些活动。
两个区域还应该指定哪个子状态是初始状态。 在我们的 tail 区域,初始状态是 not wagging。
自转换 Self-transition
自转换是指事件发生但转换返回到相同状态时。 转换箭头退出并重新进入相同的状态。
描述自我转变的一种有用方法是在过程中“一直做某事,但一直没变化”。
在狗讨好的过程中,会有一个 讨好(begging) 状态和一个 获得好处(gets treat) 事件。 而对于爱吃的狗来说,无论你经历了多少次得到 gets treat 事件,狗都会回到 begging 状态。
计划状态图 Planning statecharts
状态图的好处之一是,在将状态图放在一起的过程中,你可以发觉过程中的所有可能状态。 这种探索将帮助你避免代码中的错误,因为能让你覆盖到所有的事件变化。
而且由于状态图是可执行的,它们既可以作为图表,也可以作为代码,从而减少在图表和编码环境之间引入差异或错误解释的可能性。
为登录状态机计划一个状态图 Planning a statechart for a login machine
要绘制登录状态机的状态图,首先要列出流程中的基本事件。 想想你的登录过程会 做 什么:
- 登进 log in
- 登出 log out
然后列出由于这些事件而存在的 状态:
- 已登进 logged in
- 已登出 logged out
一旦有了一些事件和状态,状态图就开始了。
不要忘记 初始状态。 在这种情况下,logged out 状态是初始状态,因为任何新用户都会进入未登录过程。
延迟转换 Delayed transitions
作为安全措施,某些登进和登出的过程,会在固定时间后,登出非活动用户。
活动(active) 和 空闲(idle) 状态仅在用户登进时发生,因此它们成为 登进(logged in) 复合状态中的子状态。
logged in 复合状态中的初始状态是 active,因为它是 log in 事件的直接结果,登录是用户活动的标志。
延迟转换(delayed transition) 是一种在处于某种状态,达到指定时间长度后,发生的转换。 延迟的转换被标记为“之后”和一个固定的持续时间,以指示在转换到下一个指示状态之前应该经过多长时间。
在登进状态图中,60000 毫秒或 1 分钟的延迟转换跟随 active 状态来确定用户是否 idle。 如果在转换达到一分钟之前有 activity 事件,则流程返回 active 状态。
如果用户保持 idle 状态,则在空闲状态之后会延迟 180000 毫秒(或 3 分钟)转换到 自动登出(auto logged out) 状态。
动作 Actions
状态图使用,在状态图之外系统触发的 actions。 动作通常也称为 作用(effects) 或 副作用(side-effects)。 “副作用”听起来像是一个消极或不重要的术语,但引发动作,是使用状态图的主要目的。
动作事件,对后续的其余部分没有影响,事件只是被触发,流程还是原来设置的那样,走下一步。 例如,登录状态图可能会执行更改用户界面的操作。
可以在进入或退出状态或转换时触发 动作。状态的操作包含在状态容器内,带有“entry /” 或 “exit /”标签,具体取决于动作是在进入还是退出状态时触发。
在登录状态图中,idle 状态有一个进入动作来警告用户他们可能会被登出。