首页 > 课堂 > 技术开发 > 正文

UML系列内容之十:状态图

2023-06-17 18:00:45
字体:
来源:转载
供稿:网友

今天,继续我们的UML之旅。

今天,我们将浏览一下UML中的状态机图。

1.什么是状态机图

状态机图(State Machine Diagram)是系统分析中常用的一种工具,它用于描述一个对象在其生命周期内所经历的各种状态,以及状态之间的转移、引发转移的事件或状态转移的活动。

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

2.状态机的构成

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

2.1 状态

状态(state)是指对象在其生命周期中,满足某些条件、执行某些活动或等待某些事件时的一个状况。

如图书馆的一本书籍可能有:“在架”、“借出”、“被预借”等状态;读者可能有“已绑定借阅卡”、“未绑定借阅卡”、“被限制借阅”等状态。

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

借阅图书状态
图1 借阅图书状态

如上图是借阅系统中借阅图书的一个状态。

entry、do和exit是标准的三个动作,分别是进入状态时的动作,处于该状态下执行的动作和退出该状态时的动作

且可以在该状态下定义相应的事件动作event。

entry为进入动作,当进入该状态时要执行的动作

exit为退出动作,当离开当前状态时要执行的动作

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

(1)初始状态

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

初始状态
图2 初始状态

(2)结束状态

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

结束状态
图3 结束状态

(3)组合状态

组合状态是状态内部嵌套有子状态的状态。一个组合状态包含一系列子状态。

而没有嵌套的状态称之为简单状态。

嵌套在一个状态内部的状态为子状态。可以根据状态是否同时存在,可以再细分为顺序子状态和并发子状态。

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

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

并发状态之顺序子状态
图4 组合状态之顺序子状态

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

并发状态
图5 组合状态之并发子状态

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

历史状态
图6 组合状态之历史状态

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

2.2 转移

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

状态转移
图7 状态转移

一个转移一般包括源状态、目的状态、触发事件、警戒条件和动作5部分组成。

也就是说事件的发生导致了从源状态到目的状态的转移。

(1)源状态

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

(2)目的状态

转移完成后的状态。

(3)触发事件

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

(4)警戒条件

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

(5)动作

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

状态转移
图8 动作

上图中是图书由“在架”状态转移到“被预借”状态的一个例子。

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

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

外部转移:外部转移是一种改变状态的转移。也是状态机中常见的一种转移。

这种转移主要出现在两个不同的状态之间。

内部转移:内部转移是指不会导致状态改变的转换。有时,我们需要在该状态下处理一些无需离开状态的事件,这时可以定义一个内部转移。

如“借阅图书”这个状态中,“超出借阅册数”时,我们可能终止该本书的借阅,不把本书添加到借阅列表中,这种处理没有导致借阅图书状态的转移,可以视为内部转移。

内部转移的表示方法:

事件(参数名)[警戒条件]/动作

如下图所示的三个event动作。

状态中的动作
图9 借阅图书的状态动作

如果源状态与目的状态是同一状态,则称为自转移。

下面这个例子中的“循环”就是一个自转移的例子。

自转移
图10 自转移

2.3 事件

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

主要包括信号事件、时间事件、改变事件和调用事件等。

(1)信号事件

信号事件(signal event)是指一个对象接收到信号的事件,该接收信号的事件会导致其状态的转换。

发送对象明确地创建、初始化一个信号实例并把它发送到一个对象或对象的集合。

信号事件
图11 在选择记录时,按下ctrl进入多选模式状态,释放ctrl键转换为单选模式

(2)时间事件

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

时间事件
图12 在路灯控制系统中,上午6:00断电关闭,下午18:00后供电,开灯

(3)改变事件

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

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

改变事件
图13 登录后,time自动连续增加,未操作时间超过300秒取消登录状态

(4)调用事件

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

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

2.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)不可中断动作:[用语言说明]

3.状态图建模步骤

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

(1)确定建模的语境

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

(2)识别状态

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

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

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

(4)确定状态中的其它动作

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

(5)确定状态之间的转移

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

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

(7)进行必要的优化

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

4.使用Rose创建状态图

4.1 新建状态图

在Rose中,可以为一个类、一个用例或一个参与者建立状态图,也可以为一个子系统或整个系统建立状态图。

在Rose中,状态图可以创建在用例视图或逻辑视图里。

如果为某一个对象,如类、用例或参与者,可以直接在左侧对象浏览器中的该对象上右击,然后选择“New”(新建)->"Statechart Diagram"(状态图)。

新建状态图
图15 为一个对象建立状态图

若不指定对象,也可以在逻辑视图或用例视图上右击选择“New”->“Statechart Diagram”。

新建状态图02
图16 在逻辑视图上新建状态图

新建完状态图后,可以直接给其重新命名。或者通过右击新建的状态图,然后选择“rename”,如下图所示:


图17 为状态图重命名

4.2 状态图的工具箱

通过在左侧对象浏览器中,双击新建的状态图可以开始工作了。

同时,在中间显示出用于状态图的工具箱,默认的工具箱及其含义如下:

状态图工具箱
图18 状态图工具箱

用户也可以在工具箱上右击后选择“Customize...”来添加其它的工具,如下图所示:

定制状态图的工具箱
图19 自定义工具箱

用户可以在左侧选中一个工具,然后点击“添加(A)->”,将其添加到工具栏中,也可以把不需要的工具在右侧选中之后点击“<-删除(R)”将其删除掉。

在左侧待选工具中,“—”是用于创建一个水平的同步条,“|”用于创建一个垂直的同步条,“◇”用于创建一个判定。

定制好自己的工具箱后,可以点击“关闭”按钮将其关闭。

4.3 创建状态

(1)创建

用户在工具箱中点击状态工具,然后在右侧工作区中点击一下,就会创建一个状态。

(2)修改名称

方式一:创建完状态,其默认名称会默认被选中,这时,用户可以直接修改其名称;

方式二:在创建完以后要修改其名称,可以先选中这个状态,然后再次点击一下,也可以修改其名称;

方式三:在状态上双击,弹出如下对话框:

状态通用选项卡
图20 状态图规范说明对话框

在其“General”(通用)选项卡上的Name(名称)项中修改其名称;

方式四:右击该状态,然后选择“Open Specification...”,也会弹出上图所示的对话框。右击状态选择的情形如下图所示:

Rose中右击一个状态
图21 右击状态图选择“打开规范说明...”

(3)删除一个状态

如果想彻底删除一个状态,可以选中状态后,按下“Ctrl + D”,这样就把这个状态彻底从模型库中删除了。

也可以在状态上右击,然后选择“Edit”(编辑),再选择“Delete from Model”,也可以把这个状态从模型库中彻底删除。

用户还可以在选中状态后,通过菜单中的“Edit”菜单下的“Delete from Model”从模型库中删除该状态。

Rose中右击删除一个状态
图22 右击选择删除状态

如果仅是从当前图中删除状态,而非从模型库中彻底删除,用户可以在选中状态后,按下键盘上的“Del”(删除键)进行删除,也可以在状态上右击,然后选择“Edit”->"Delete",如上面的图中的Delete,也可以选择菜单中的“Edit”->“Delete”来删除一个状态。

(4)为状态添加动作

用户可以双击一个状态或右击状态选择“Open Specification”打开状态规格说明对话框。打开的状态规范说明对话框如图20所示。

在“General”选项卡中可以设置状态的名称、构造型、说明文档、是否激活历史状态(浅层)或深层历史状态。

在第2个选项卡“Actions”中可以添加状态的动作,如下图:

Rose中Actions选项卡
图23 Actions选项卡

在空白处右击,选择“Insert”,可以为其添加一个动作。

Rose中为状态添加动作
图24 为状态添加动作

添加后的动作如下图所示:

Rose中添加动作后的效果
图25 添加动作后的效果

我们可以在动作所在的行上双击或右击后选择“Specification...”,其会弹出如下图所示的对话框:

Rose中关于动作的规格说明
图26 动作的规格说明

在该对话框中的“When”对应的下拉列表中可以设置动作的类型,其中“On Entry”代表进入动作,“On Exit”代表退出动作,“Do”代表内部执行的活动,“On Event”代表内部事件转移。Type用于指定动作的类型是一个普通动作(Action)还是发送一个事件(Send Event)。

当“When”中选择的是“On Event”时,在“When”下边的“On Event”分组框中可以设置事件的名称、参数和条件。

下图是On Event的一个设置情景:

Rose中OnEvent的设置
图27 动作规格说明的例子

下图是对“已借出”状态设置的相关动作。

Rose中已借阅状态的设置情况
图28 设置了动作的状态规格说明

4.4 添加转移

在工具相中选择“状态转移”工具,鼠标会变为一个向上的空心箭头的形状,这时,在源状态上按下鼠标不放,滑动到目的状态上后松开鼠标即可。

下图给出了鼠标到达目的状态松开之前的一个情景。

Rose中添加状态转移的操作
图29 添加状态的转移

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

图片Rose中添加状态转移后的效果
图30 添加了状态转移后的样子

设置转移的相关内容

方式一:选中转移后,右击后选择“Open Specification...”,如下图所示:

Rose中转移的设置
图31 右键打开转移的规格说明

方式二:双击转移。

两种方式都会打开下图所示的状态转移规格说明对话框:

Rose状态转移设置-通用选项卡
图32 转移的规格说明——General

在上面图中“General”选项卡的Event行中添加触发转移的事件,在Arguments行中添加事件的参数。

在“Detail”选项卡中可以对触发事件进行详细的设置,如下图:

Rose中设置转移-Detail
图33 转移个规格说明——Detail

设置的内容包括“Guard Condition(警戒条件)”、“Action(动作)”以及发送的事件、发送事件的参数和发送的目标对象。

若在General和Detail设置的内容如图34和图35中的样子,则最后在源状态和目的状态中呈现的样子如图36所示:

Rose中设置转移的例子-通用选项卡
图34 转移规格说明例子——General设置

Rose中设置转移的例子-Detail选项卡
图35 转移的规格说明——Detail设置


图36 状态转移设置的最终样子

4.5 子状态的创建

在添加了主状态之后,可以在其主状态中,添加子状态,方法是在工具箱中选择状态后,直接在主状态上点击即可,则在主状态中会添加一个子状态。

下图显示了当选择状态工具后,鼠标滑到主状态上时的情形:


图37 添加子状态

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

Rose中添加子状态的效果
图38 子状态效果

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

4.6 如何设置历史状态

打开状态的规格说明对话框(双击状态或右击选择“Open Specification...”),在“General”选项卡中把下面的“State/activity history”勾选上,则会在状态的左下角显示一个带圈的H,如果想激活状态的深层历史状态,就把“Sub state/activity history”也勾选上,则原来H字母的右上角出现一个“*”号。

设置历史状态的情形如下:

Rose中历史状态的设置
图39 设置历史状态

状态设置后的效果如下图所示:

Rose中历史状态效果
图40 历史状态

4.7 如何添加同步条

用户可以使用本文中4.2中的方法,把水平同步条以及垂直同步条添加到工具箱中,在需要的时候选择它后并在绘图区点击一下,即可以添加一个同步条。

用户也可以通过菜单栏中的“Tools”->“Create”中的“Horizontal Synchronization Bar”及“Vertical Synchronization Bar”创建水平同步条或垂直的同步条。如下图所示的菜单:

Rose中为状态图添加同步条
图41 使用菜单添加同步条

4.8 关于初始状态和结束状态

若要创建初始状态,用户可以直接在工具箱中选择黑色的实心圆,在绘图区点击一下就可以创建一个初始状态。

注意:一个状态图中只允许有一个初始状态,如果在一个绘图区中要使用多次初始状态,用户可以从左侧浏览器中把它拖拽到绘图区 中来。

创建结束状态的方法与创建初始状态的方法相同。

在一个状态图中,可以有多个结束状态

以上带大家学习了UML中的状态机图以及使用Rose绘制状态图的方法。

如有问题,请留言。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表