免费注册
首页 知识社区 『这就是UML!』系列内容第9讲:状态图

『这就是UML!』系列内容第9讲:状态图

特邀撰稿人:翔宇亭IT乐园 2024-5-31
486

状态图和活动图是状态机的两种表现形式,利用状态机可以精确地描述对象的行为。状态机用于对模型元素的动态行为进行建模,或是说对系统中受事件驱动的方面进行建模。

从对象的初始状态起,开始响应事件并执行某些动作,这些事件引起状态的转换;对象在新状态下又开始响应事件和执行动作,如此连续进行直到终结状态。

状态图用途

状态图主要用于对类或对象的动态行为进行建模,也可以对一个用例,或整个系统进行建模。

用户管理状态图

状态图要素

状态图由状态、转移、事件和动作等组成。

1. 状态

状态(state)是指对象在其生命周期中,满足某些条件、执行某些活动或等待某些事件时的一个状况。比如图书馆的一本书籍可能有:“在架”、“借出”、“被预借”等状态,读者可能有“已绑定借阅卡”、“未绑定借阅卡”、“被限制借阅”等状态。

在UML中,状态使用圆角矩形表示,一个状态有自己的状态名称,状态中包含该状态下将执行的动作和事件。下图是借阅系统中借阅图书的一个状态:

借阅图书状态

 entry、do和exit是标准的三个动作,且可以在该状态下定义相应的事件动作event。

entry为进入动作,当进入该状态时要执行的动作;do为执行动作,处于该状态下执行的动作;exit为退出动作,当离开当前状态时要执行的动作。

除了这种标准状态之外,UML中还定义了初始状态、结束状态、组合状态、子状态和历史状态。

(1)初始状态

初始状态代表状态机图的开始,使用实心圆表示。一个状态机图只有一个初始状态。

初始状态

(2)结束状态

结束状态表示一个状态机图的结束,使用实心的圆环表示。一个状态机图可以有多个结束状态。

结束状态

(3)组合状态

组合状态是状态内部嵌套有子状态的状态。一个组合状态包含一系列子状态,没有嵌套的状态称之为简单状态,嵌套在一个状态内部的状态为子状态。可以根据状态是否同时存在,可以再细分为顺序子状态和并发子状态。

顺序子状态:在组合状态的生命周期中,任何时刻只能处于一个子状态,即多个子状态之间是互斥的关系,不能同时存在。

如下面的图中演示一部手机处于“给某人打电话”这种组合状态时,其子状态不能同时存在,是一种顺序的子状态。

给某人打电话组合状态之顺序子状态

并发子状态:多个顺序的子状态可以同时存在。下图给出一辆汽车行驶中的组合状态,低速和高速这两个状态是顺序的子状态,在某一时刻只能处于其中一个状态,前进和倒车也是如此,但这两个顺序的子状态又可以同时存在。

汽车行驶组合状态之并发子状态

历史状态:历史状态是一种伪状态,它表示在状态再次转移到该组合状态时,应处于上一次退出时的一个子状态。

音乐播放器组合状态之历史状态

上图给出了一个音乐播放器的一个状态机图。其中“播放”标记为历史状态,其含义是在播放状态转移到暂停状态,当由暂停再进入播放状态时,其应进入“播放”状态退出时的一个子状态,它可能在退出时是“顺序播放”状态,也可能是“随机播放”状态,也可能是“倒序播放”状态,但必须是退出“播放”状态时所处的一个历史状态。

2. 转移

转移(Transition)指的是两个不同状态之间的一种关系,是对象在满足一定条件或发生某个事件时,从一种状态迁移到另外一种状态。

状态转移

一个转移一般包括源状态、目的状态、触发事件、警戒条件和动作5部分组成,也就是说事件的发生导致了从源状态到目的状态的转移。

(1)源状态

是受转移影响的状态,当事件发生或满足警戒条件时,就会激活一个转移。

(2)目的状态

转移完成后的状态。

(3)触发事件

当源状态的对象接收到事件时转移才有可能被激活。触发事件有自己的名称,也可以有自己的参数。

(4)警戒条件

转移激活前需要满足的一个条件。警戒条件往往是一个逻辑表达式,其值为真或假。触发事件发生,且警戒条件为真时,转移才会被激活。否则,本次事件将被丢弃,只能等待下一次触发事件的发生。

(5)动作

当转移被激活时,对应的动作也会被执行。动作一般可以是一个赋值操作或算术运算,也可以是调用目的对象的一个操作或创建、销毁一个对象,也可以是用简单语言来说明动作的含义。

“在架”状态转移到”被预借“状态

上图中是图书由“在架”状态转移到“被预借”状态的一个例子。源状态是“在架”,目的状态是“被预借”,“读者预借”是触发事件的名称,“图书编号”是触发事件的参数,“读者预借数量<=1”是转移的警戒条件,“添加预借记录”和“设置图书预借标志=1”是转移伴随的动作。

转移还区分外部转移和内部转移两种情形:

外部转移:外部转移是一种改变状态的转移,也是状态机中常见的一种转移,这种转移主要出现在两个不同的状态之间。

内部转移:内部转移是指不会导致状态改变的转换。有时,我们需要在该状态下处理一些无需离开状态的事件,这时可以定义一个内部转移。比如“借阅图书”这个状态中,“超出借阅册数”时,我们可能终止该本书的借阅,不把本书添加到借阅列表中,这种处理没有导致借阅图书状态的转移,可以视为内部转移。

内部转移的表示方法:事件(参数名)[警戒条件]/动作。如下图所示的三个event动作:

借阅图书内部转移

如果源状态与目的状态是同一状态,则称为自转移。下面这个例子中的“循环”就是一个自转移的例子:

自转移表示方法

3. 事件

事件(Event)是指在特定时间或空间内出现,并能够导致状态转移的信号、超时、条件改变、时间段等,主要包括信号事件、时间事件、改变事件和调用事件等。

(1)信号事件

信号事件(signal event)是指一个对象接收到信号的事件,该接收信号的事件会导致其状态的转换。发送对象明确地创建、初始化一个信号实例并把它发送到一个对象或对象的集合。

信号事件

在选择记录时,按下ctrl进入多选模式状态,释放ctrl键转换为单选模式。

(2)时间事件

时间事件(time event)代表时间的流逝。当时间条件被满足时可能要触发某个事件。时间可以是相对的也可以绝对的。如:after(9:00)。

时间事件

在路灯控制系统中,上午6:00断电关闭,下午18:00后供电,开灯。

(3)改变事件

改变事件(change event)是指依赖特定属性值的逻辑表达式所表示的条件满足时,事件发生。

这里的改变事件与上面所说的警戒条件不同,警戒条件是在转移事件发生时或事件接收者对事件处理时被赋值一次,如果警戒条件为假,则转移就不会发生,且该事件会被丢弃,警戒条件也不会再给赋值;而改变事件会被多次赋值直到条件为真,从而激活转移。可以使用when(exp)的形式来表示。

改变事件

time自动连续增加,未操作时间超过300秒取消登录状态。

(4)调用事件

调用事件(call event)表示一个对象接收到一个对调用的请求,这个对象用状态的转移而非特定的处理过程来实现操作。操作的参数即是事件的参数。调用结束时,被调用者将返回结果给调用者,调用者可以继续执行。

调用事件

借阅图书状态中如有未交清罚款进入到缴纳罚款状态,缴纳罚款完毕后返回缴清标志,借阅图书状态继续保持。

4. 动作

动作通常是一个简短的计算处理过程,如赋值操作或算术运算。动作也可以是一个动作序列,包括给另外一个对象发送消息、调用一个操作、设置返回值、创建或销毁对象。

动作具有原子性,所以动作不可被中断,不能被同时发生的其它动作所影响或终止。动作运行时间很短,不能再被插入其它事件。

各种动作的种类及相关语法可描述如下:

(1)赋值:target:=expression

(2)调用:opname(arg1,arg2)

(3)创建对象:new Cname(arg1,arg2)

(4)销毁对象:object.destroy()

(5)返回值:return value

(6)向对象发送消息:sname(arg1,arg2)

(7)对象自我终止:terminate

(8)不可中断动作:[用语言说明]

状态图建模

在状态图建模过程中可以参考以下步骤:

1. 确定建模的语境

状态机可以用于对类进行建模,也可以为一个用例进行建模或者为一个子系统,甚至整个系统建模。我们可以遵循从小到大的原则进行建模,从类的状态到用例,再到子系统的过程。当然,并不是每个类都需要建立状态机;

2. 识别状态

确定好建模的语境后,识别其可能的状态,识别状态可以按照从粗到细的方法去识别,并确定出必要的状态;

3. 确定状态的进入动作和退出动作

对每个状态确定其是否需要进入动作和退出动作;

4. 确定状态中的其它动作

确定建模对象在该状态下是否有其他需要做的事情以及警戒条件等;

5. 确定状态之间的转移

识别出各个状态之间转移的条件或事件,以及警戒条件等;

6. 检查所绘制的状态机是否与实际相符

7. 进行必要的优化

优化包括图形的布局,图形的形式,以及状态是否有冗余等。

使用ProcessOn绘制状态图

1. 新建UML状态图

注册/登录ProcessOn后,进入个人文件页,点击“新建”按钮创建一个空白UML文件,如下图所示的操作:

创建UML空白文件

2. 创建状态图中的图形元素

创建完UML图后,在编辑器界面的左侧可以看到图形组件区,该区域包含了创建状态图/活动图用到的基本绘图工具。用户可以在左侧图形组件区选中一个图形元素,然后拖拽其添加到右侧空白编辑区。

UML状态图/活动图图形元素

在左侧图形组件区中,“—”是用于创建同步条的图形,“◇”是用于创建一个判定的图形。

3. 创建状态

用户绘图时可以直接从编辑器左侧的图形组件区拖拽图形到编辑器空白区域,即可完成图形的创建。然后可以选择图形后通过编辑器顶部工具栏和右侧的工具面板对图形相关属性进行设置。

创建状态

4. 删除状态

如果想删除一个状态,可以选中链之后,按下“Delete”或“Backspace”键,或者在状态上右击,然后选择“删除”,则可以彻底删除该链。

删除状态

5. 添加状态转移

绘制状态转移的方法是使用快捷键“L”,或者在左侧图形组件区的基础图形中拖拽“直线”元素到编辑器空白区域,然后点击生成的线条后,在工具栏上方设置线条的颜色、粗细和箭头样式。另外,也可以直接选中源状态的一端,按下鼠标不放,滑动到目的状态上后松开鼠标即可。下图给出了鼠标到达目的状态松开之前的一个情景:

添加状态转移

松开鼠标之后的效果如下图所示:

添加状态转移后效果

设置转移的相关内容

方式一:双击转移后,直接添加内容,比如触发条件、“Guard Condition(警戒条件)”、“Action(动作)”以及发送的事件、发送事件的参数和发送的目标对象。则最后在源状态和目的状态中呈现的样子如图所示:

直接添加转移内容

方式二:从编辑器左侧图形组件区拖拽文本元素到右侧编辑区。

直接拖拽文本元素添加转移内容

6. 子状态的创建

在添加了主状态之后,可以在其主状态中,添加子状态。方法是右击状态图形,将其位置设置为置底,再从编辑器左侧图形组件区中拖拽状态在其上方,则在主状态中会添加一个子状态。下图显示了当右键单击状态图形后,将其置于底部的情形:

子状态置于底层

下图显示了添加完后的情形:

添加子状态后效果图

给子状态添加转移等方法与上面有关内容相同。

7. 添加历史状态、同步条

从编辑器左侧的图形组件区的状态图中,拖拽一个带圈的H到状态的左下角,即可成功添加历史状态。状态设置后的效果如下图所示:

添加历史状态效果图

另外,添加同步条也是从右侧状态图的组件区拖拽到右侧编辑区即可。

8. 关于初始状态和结束状态

若要创建初始状态,用户可以直接在左侧图形组件区中选择黑色的实心圆,拖拽到右侧编辑区,即可创建一个初始状态。

注意:一个状态图中只允许有一个初始状态,如果在一个绘图区中要使用多次初始状态,用户可以从左侧图形组件区中把它拖拽到编辑区中来;创建结束状态的方法与创建初始状态的方法相同。在一个状态图中,可以有多个结束状态。




往期内容推荐

这就是UML——第1季 UML简介

这就是UML——第2季 UML通用知识上:事务、关系和公共机制

这就是UML——第3季 UML通用知识下:视图和图

这就是UML——第4季 用例图

这就是UML——第5季 用例图案例学习

这就是UML——第6季 类图

这就是UML——第7季 序列图

这就是UML——第8季 协作图

免费在线协同思维导图流程图 免费使用