计算机的简单理论模型到有限状态机
执行打开闸机动作。转换还有一个监护条件逻辑测试——或布尔测试,只有测试通过时转换才发生。
而事件可以是外部事件和内部事件,外部事件是在系统和它的执行者之间传递的事件,比如,按下一个键和一个来自传感器的中断都是外部事件。内部事件是在系统内部的对象之间传送的事件,比如,溢出异常是一个内部事件。可以用UML对4种事件建模:信号、调用、时间推移或状态的一次改变。信号或调用可以带有参数,参数值对转移(包括监护条件和动作的表达式)是可见的。
信号是一个异步事件,在实例间异步传递消息的通信规约。消息是一个具名对象,信号是消息的类型,象类一样,信号也有属性和操作。而信号事件是指发送或接收信号的事件,其差别在于信号是对象之间的消息,而信号事件是指在某时某刻发生的事情。
如果事件没有产生任何效果,则FSM保持状态不变。通常下一个状态依赖于当前状态和输入事件,有时状态转移会导致输出动作。在某些情况下,虽然一个事件不会立即导致状态转换,但它会影响随后的状态转换。如果事件已经产生,则可以将该情况保存为一个条件,在之后进行检验。
监护条件是由一个方括号括起来的布尔表达式,放在触发器事件的后面。其表示法为"事件[条件]"(Event[Condition]),条件是某一段时间内值为True或False。通常"事件"引起了"状态转换",当事件发生时,为了发生转换,可选的"条件"的值必须为True,可选的"动作"作为结果被执行。
动作是与状态转换相关的可选的输出,动作执行了计算(调用相应的函数),作为状态转换的结果。事件导致状态转移,而动作是状态转移所产生的效果。动作在状态转移时被触发,执行后自行终止。
● 转换动作
转换动作是指从某一状态转换为另一状态时产生的动作,该动作也可能发生在状态转换至自身状态时。为了描述状态图中的动作,将状态转换表示为:事件/动作(Event/Action)或事件[条件]/动作(Event[Condition]/Action),比如,card/unlock。
考虑闸机状态图中的动作:当事件card发生时,闸机从Locked状态转换为Unlocked状态,发生在该状态转移中的动作是获取card信息。作为状态机的输出,该动作显示票价和余额并开锁。
通常多个动作可以和同一个状态转换关联,因为动作都是并发执行的,所以这些动作之间不能有任何的相互依赖关系。比如,不能同时发生两个并发的事件——计算余额和显示余额,因为这两个动作有先后顺序的依赖关系,在余额计算之前不无法显示出来。为了避开这个问题,可以引入"计算余额"的中间状态。动作"计算余额"在进入该状态时执行,动作"显示余额"在退出该状态时执行。
● 进入动作
进入动作是指在开始进入该状态时触发的即时动作,使用保留字"进入(entry)"表示,在状态框里表示为"进入/动作(entry/Action),即entry/[action-list]。"
● 退出动作
退出动作是指在离开该状态时触发的即时动作,使用保留字"退出(exit)"表示,在状态框里表示为"退出/动作(exit/Action),即exit/[action-list]。"
实例分析由于状态图源自于用例,因此要从用例开发状态图。首先需要用例中的一个特定的场景,即从用例中的一条特定路径描述对象之间的交互,正常的业务序列详见图 4.8(a)。
图 4.8 闸机业务序列图
如果闸机在Locked状态收到card事件,则转移到Unlocked状态并执行unlock动作,此时闸机将它的状态改为Unlocked并调用unlock函数;如果闸机在Unlocked状态收到一个pass事件,则转移到Locked状态并执行lock动作,此时闸机将它的状态改为Locked并调用lock函数。
如图 4.9 (a)所示为正常的业务序列图对应状态图,由于闸机处于打开状态或关闭状态时,"card()"或"pass()"操作对应的处理是不同的,因此难以用一个序列图清晰地描绘对象交互与状态的关系。如果以业务实体(闸机)的状态(打开状态或关闭状态)为核心,将执行者与系统交互的具体操作称之为"事件",比如,card()、pass()等。
图 4.9 闸机状态图
表4.1 闸机状态转移表
状态 | 事 | 状态 | 动作 |
这些图是由状态、事件、转换和动作组成的有向图,圆角矩形表示闸机的状态,闸机始终保持状态直到转换促使它改变状态。转换用导向箭头表示,通常由收到触发事件的元素发起。当输入的事件与有向边上的事件匹配时,闸机将会从一个状态转换到另一个状态。
其中包含了起始状态、触发转移事件、终止状态和要执行的动作,将其转换为状态转移表的表格,详见表 4.1。由于状态转移
- 电源软启动的实用设计技巧(07-16)
- 周立功:动态分布内存——malloc()函数与calloc()函数(07-22)
- 周立功“程序设计与数据结构”:深度解剖动态分布内存的free()函数与realloc()函数(07-25)
- 周立功教你学程序设计技术:做好软件模块的分层设计,回调函数要这样写(07-30)
- 周立功教你学C语言编程:教你数组是如何保存指针的(07-31)
- 算法的泛化问题,这些坑你可能都经历过!|周立功教你学软件设计(08-01)