状态机描述一个事物在其生命期中,所具有的状态,以及因事件触发而引起的状态的各种转换。
状态机从对象的初始状态开始,响应事件并执行某些动作,从而引起状态的转换;在新状态下又继续响应事件并执行动作,如此循环进行到对象的终结状态。
状态机主要由状态、转换、事件、动作几部分组成。
1)状态表示对象的生命周期中的一种条件或情况。
2)转换表示两种状态间的一种关系。
3)事件表示在某一时间与空间下所发生的有意义的事情。
4)动作表示一个可执行的原子操作,是UML能够表达的最小计算单元
在UML表示法中,一个状态转换图被称为状态机图。
参考:《软件建模与设计: UML、用例、模式和软件体系结构》
在UML表示法中,圆角框表示状态,连接圆角框的弧线表示转换。
初始状态(initial state)用一个小黑圆圈表示。
终结状态(final state)是可选的,它被描绘为嵌套在大白圈中的小黑圆圈,有时也被称为靶心(bull’s-eye)。
状态图可以按层次分解,将一个组合状态分解成为一组子状态。
在表示状态转换的弧线上,使用“事件[条件]/动作(Event[guard]/Action)”进行标记。
事件(event)引起了状态的转换,当事件发生时,为了发生转换,可选的布尔条件(guard)必须为真。可选的动作(action)作为转换的结果被执行。
一个状态可具有以下任意的动作:
进入动作(entry action),它在进入状态的时候执行
退出动作(exit action),它在退出状态的时候执行
发生事件(Event)后,根据当前状态(Current State)决定执行的动作(Action),并设置下一个状态(Next State)。
再具体一点就是当事件(Event)发生后,匹配当前状态(State)是否有对应事件(Event)且满足警备条件(Guard)的转换(Transition),如果有则执行该转换的Action动作并设置状态为目标状态。其中转换遵循下文所述的转换继承和转换覆盖原则。
三个特性
状态(States):表示对象在其生命周期中的某个阶段、条件或状况,包括状态名、内外部转换、进入退出动作等。
状态指事物在其生命周期中满足某些条件、执行某些操作或等待某些事件而持续的一种稳定的状况。用圆角矩形标识。
内部结构:状态的内部结构可以由以下部分组成,除状态名外其他都是可选的,根据实际情况而定
- 状态名(State Name): 状态名称
- 进入/退出动作(Entry/Exit Action): 进入和退出动作
- 内部转移(Internal Transition): 不会发生状态的转移
- 内部动作(Do Action): 状态保持不变时执行的动作
- 子状态(Submachine State): 适用于复合状态场景
- 延迟事件(Deferred Event): 在本状态下暂时不处理,但不被丢弃,而是延迟到其他状态中处理的事件
初始状态(initial state):简称始态,表示状态机的起始,用实心圆点标识。
初始状态表示一个状态机从此结点开始,但事物不会在此状态停留,会立即转换到初始状态所连接的下一个状态。
初始状态只有输出,没有输入。
终止状态(final state):简称为终态,表示一个状态机、一个复合状态,或一个区间状态的结束。终止状态用圆形内嵌圆点(“牛眼”bull’s-eye)符号表示。一个状态图可以由多个结束状态。
复合状态(Compound States):包含子状态的状态。
一个状态可以被嵌套在另一个状态之中,被嵌套的状态叫子状态,包含子状态的状态就称为复合状态。
事物在复合状态时,意味着它处于其中一个子状态;事物如果在某一个复合状态的子状态,它一定处于该复合状态。
一个复合状态或子机状态也有其始态。一个状态机可以有多个始态,存在多个始态的状态机一定存在状态的并发,在并发状态的一个区间只能有一个始态。
复合状态具有始态,转入一个复合状态等价于转入其始态。
复合状态可以有终态,达到复合状态的终态,将从复合状态转出。
控制节点包括:分叉(Fork)与汇合(Join)、汇接(Junction)、选择(Choice)、历史(History)状态。
指将一个转换分成两个或多个转换,用来描述需要并发的状态。
指将从并发状态来的转换合并形成一个转换,用来描述多个并发状态的控制同步。
一个状态可以被划分为包含多个同时存在和执行的子状态的区域。下面的例子表明,在“Applying Brakes”状态下,前后制动器将同时独立运行。注意 fork 和 join 伪状态的使用,而不是选择和合并伪状态。这些符号用于同步并发线程。
用来汇接多个转换,以简化转换路径。
汇接的符号与初始状态的符号相同,但它允许连接多个转换的输入和多个输出。
用来实现根据条件判断,转换到不同目标状态。
用菱形表示选择,有一个输入边到选择,多个输出边由选择到目标状态结点。
为一个状态机或复合状态提供了一种在退出状态时记忆当前活动所处的子状态,并能够返回到该子状态的机制。
历史状态用于复合状态场景中中断退出时记忆子状态,下次可以直接越过外层状态直接进入子状态。
- 浅历史状态(Shallow History State):只记住复合状态最外层的历史。用圆圈内部 H 标识
- 深历史状态(Deep History State):记住复合状态所有层次子状态的历史。用圆圈内部 H* 标识
历史状态是应用于复合状态的一种伪状态,它代表上次离开该复合状态时的最后一个子状态。
深历史状态恢复复合状态中最后激活的叶子节点状态,浅历史状态只恢复到复合状态的直接自状态中那个最后激活的状态。
此图中,如果最后激活的状态是D,浅历史状态恢复到B,深历史状态恢复到D。
动作(Actions):可执行的原子级操作。用正斜杠后间隔的文字标识,如Event[guard]/Action。
事件(Event):指发生的能引起状态变换瞬时事情。可分为调用事件、变化事件、时间事件和信号事件等。
警备条件(guard):布尔表达式,决定是否激活转换。不是所有的事件都会引起状态转移。
转换(Transitions):状态之间在某个事件或条件驱动下的切换过程。
转换是两个状态之间的一种有向关系,表示从源状态转换到目标状态。
状态转换用一个带箭头的实线表示,箭头由源状态指向目标状态。
4.6.1 状态转换的要素
- 初态:转换前的状态
- 触发事件:转换的触发条件
- 警备条件(Guard Condition):布尔表达式,决定是否激活转换。不是所有的事件都会引起状态转移。
- 动作:转换激活时的操作
- 次态:转换后的状态
4.6.2 转换分类
- 外部转换:对事件(Event)做出响应,执行相应的动作(Action),引起状态(State)变化。格式:事件(参数)[警备条件]/动作
- 内部转换:对事件(Event)做出响应,执行相应的动作(Action),但并不引起状态(State)变化。格式:事件(参数)[警备条件]/动作 用单向弧形箭头标识
- 默认转换:进入初始态触发其默认转出、进入终止态触发其父状态默认转出,进入历史状态触发其上次记忆状态或默认状态,进入复合状态默认转到其初始态。
- 进入转换:当进入某个状态(State)时执行某个动作(Action)。格式:entry/动作
- 退出转换:当退出某个状态(State)时执行某个动作(Action)。格式:exit/动作
常规转换
常规转换需要事件触发,执行转换时可能会附带执行进入转换、退出转换或默认转换。
当进入到某个状态时会自动执行该状态的进入转换,当退出状态时自动执行其退出转换;
当前状态匹配到事件Event和警备条件Guard为真或无警备条件时执行对应的转换,该转换可以使内部转换或外部转换。
当前状态没有匹配到转换但其父状态可以匹配到对应的事件Event及警备条件Guard为真或无警备条件的转换,则执行父状态的转换,如果父状态仍然没有匹配到但父状态的父状态可以匹配则执行父状态的父状态匹配的转换……;即当事件发生时如果子状态有匹配的转换则执行子状态的转换,否则不断向上匹配父状态的转换,直至匹配到合适的转换并执行或者所有祖先都不匹配什么转换也不执行。
默认转换
默认转换是不需要消息触发的转换。包括初始态到其默认转出、终止态到其父状态默认转出,历史状态到其上次记忆状态或默认转出,符合状态默认转到其初始态。
如果一个默认转换是从一个非复合状态出来到下一个非复合状态的,转换是自动触发的;
如果一个默认转换是从一个复合状态出来的,那么当状态转移到了复合状态的终止状态,此默认转换将被触发。即下图所示的当child-state由event触发到compound-state终止态时将触发默认转换到destination-state。
转换继承
一个状态会继承父状态的所有转换,复合状态可以减少转换的数量,如果一组状态同时都使用某个转换,则可以把他们放到一个复合状态来共享这个转换。
如在状态B1时,事件d触发,会跳到C,因为转换d会继承到B的所有子状态。
转换覆盖
转换覆盖(Transition overriding),即outgoing转换会覆盖继承的转换。
如在状态B1时,事件b触发,不会跳到C,而是跳到B2。
当状态机catch到事件(Event)发生后,与当前状态(State)匹配是否有对应事件(Event)且满足警备条件(Guard)的转换(Transition),如果有则执行该转换的Action动作并设置状态为目标状态。如果没有匹配到则用其父状态继续匹配,直到有匹配的转换为止。匹配过程遵循转换继承和转换覆盖原则。
无警戒条件或警戒条件为真,按以下顺序执行:
(1)源状态的出口活动(exit/动作),先子后父,直到源状态和目标状态的最近共同祖先(Least Common Ancestor);
(2)执行迁移上的动作(事件(参数)[警备条件]/动作);
(3)目标状态的入口活动(entry/动作),先父后子,从源状态和目标状态的最近共同祖先开始进入;
(4)改变状态为目标状态。
1)初始状态只有转出,没有转入。初始状态的转出无触发事件、无监护条件。
2)状态机最少应该有一个初态,如果存在并发可以有多个初始状态。
3)状态机最少应该有一个终态,允许存在多个终态。
4)除初态外,其他所有状态都至少应具有一个转入。
5)除终态外,其他所有状态都至少应具有一个转出。
6)一个状态机中不允许存在两个同名的状态。
1)确定对哪一个类元进行建模。
2)从类元实例的创建(始态)到被撤销(终态),确定实例可能经历的所有状态。
3)分析实例从一种状态转换到另外一种状态可能发生的事件。
4)确定当触发事件发生时,实例应该执行的动作。
5)对建模结果进行精化和细化。
6)检查与验证状态机图。
看题,状态机如下图所示。
如果对象创建之后,事件e2、e1、e3、e4、e1和e5按给定顺序发生,当所有事件发生结束后,变量x、y和z的值分别是x=____, y=____, x=____。
答案
x=-1,y=1,z=0。
这道题目覆盖了状态机图的各个知识要点。
先补充解释可能比较陌生的概念:
(1)历史状态。
历史状态(带圆圈H)记录组合状态退出时,组合状态所处于的那个子状态。浅历史状态(不带*号)只记住同一层的子状态,深历史状态(带*号)可以记住更深层的子状态。
历史状态有向外的迁移,表示如果历史状态空白,那么迁移到指定的默认目标状态,否则迁移到原来记忆的状态。这个地方经常有人误解,误以为迁移到历史状态就等于迁移到历史状态向外迁移所指向的目标状态,如果是这样,中间插入一个历史状态不是多此一举吗?
使用场景示例。比如微xin应用,在浏览公众号网页、小程序等页面时点击新消息通知进入聊天状态,当前窗口会收为浮窗,点击悬浮窗可返回历史状态,即浏览状态的阅读页面及位置等。
(2)迁移过程。
不带触发事件的迁移,在到达状态的终态时隐式触发。再说一下执行顺序。
无警戒条件或警戒条件为真,按以下顺序执行:
(1)源状态的出口活动,先子后父;
(2)迁移上的动作和消息;
(3)目标状态的入口活动,先父后子;
(4)改变状态。
解析
本题来自Martina Seidl等所著的“UML @ Classroom”。
一开始,状态机缺省进入A。在进入A之前,执行迁移上的动作x=2。进入A时,执行A的入口活动z=0。
当e2发生,状态机离开A迁移到C。离开A时,执行A的出口活动z++,z值为1。然后,执行迁移上的动作z=z*2,z值为2。进入组合状态C时,执行C的入口活动z++;y=2。z值为3,y值为2。C的缺省子状态是C1,状态机进入C1,执行C1的入口活动z=z*2,z值为6。
当e1发生,状态机保持在C1,执行动作x=4,x值为4。
当e3发生,先检查迁移的警戒[z值为6]。因为z值为6,警戒[z值为6]为真。状态机离开C1,执行C1的出口活动z=3,z值为3。进入C2时,执行C2的入口活动y=0,y值为0。
当e4发生,状态机离开C2,执行C2的出口活动x=-1,x值为-1。然后,状态机离开C,执行C的出口活动y=1,y值为1。浅历史状态记住离开时所处的同一层的子状态,即C2。然后状态机进入E,执行E的入口活动y++,y值为2。
当e1发生,状态机返回历史状态,即C2。先父后子执行入口活动。先执行C的入口活动z++;y=2。z值为4,y值为2。然后执行C2的入口活动y=0,y值为0。
当e5发生,状态机离开C2,执行C2的出口活动x=-1,x的值变为-1。状态机迁移到C的终止状态,触发了完成迁移。
图上有完成迁移由C指向A。离开C时,执行C的出口活动y=1,y值为1。状态机进入A时,执行A的入口活动z=0。因此,最终x值为-1,y值为1,z值为0。
用表格表示如下:
参考
https://www.cnblogs.com/lzhdim/articles/1355858.html
UML 2 教程 - 状态机图
http://tool.uml.com.cn/ToolsEA/UserGuide/model_domains/historystate.html
Enterprise Architect user guide
上一篇:学习Java——枚举
下一篇:mssqloracle数据库提权