当前课程知识点:软件工程 > 第10章 行为建模 > 10.6 状态图精讲 > 讲义视频
前面我们介绍了基本的
状态图建模的概念
下面 我们将介绍状态图建模中
涉及到层次状态机的
建模的几个更为复杂的概念
并给出一些实例
在UML状态图中
我们可以通过状态嵌套的方式
来降低图表的复杂性
一个组合状态可以包含
一或多个状态
组合状态可以实现
在不同的抽象层次上
体现状态的细节
比如定义货状态
是指在组合状态内部的状态
我们只能选其一
在这个例子中
受雇状态分为试用期和正式期
那么 一个员工要么处在
试用期要么已经转正
只能在二者选择其一
因此 我们说它是一个或状态
右边的这个是一个与状态
它也可以用于表达的是
并发状态
与状态的意思是说
当进入组合状态时
我们将在每一个组合状态中
选择一个子状态
也就是说 与状态它的子状态
就进一步的嵌套了
一个或状态的子状态
也就是说 在受雇的情况下
我们即同时拿到薪水
也会被分配到某个项目组中
完成工作
也就是拿薪水和做项目
这两件事是同时发生 并发完成
因此 它是一个与状态
也是一个并发状态
组合状态的另一个名字
叫超级状态
组合状态的好处就是
它通过把一些状态
封装到一个超级状态中
帮我们去降低复杂度
能够把一些
反复重复发生的迁移
放到组合状态下去描述
从这个图中我们可以看到
上边是一个简单的状态图
下边是一个带有组合状态的图
通过组合状态
我们把busy dial tone
ringing和connected四个状态
封装到了一个统一的超级状态
叫off hook里边
也就是说 将电话占线
拨号 响铃和连接四种状态
统一封装成了一个摘机状态
而这个时候由刚才的四个状态
向空闲状态发出的所有迁移
就被放到方框的外面
发一条迁移就可以了
因此 我们可以看出
带有组合状态的状态机图
和不带组合状态的状态机图
其实在语意上是相等的
组合状态只是一种文法上的转换
因此 它的表达能力
和原来是一样的
这里给出的是另外一个
组合状态的例子
我们将人的成年阶段
定义为组合状态
并在其中用虚线分割了
两个与状态
在这个与状态中
我们分别从一个人的工作年龄
和他的婚姻状态
定义一个人他的状态
在每一个单独的与状态的
分支下边
都是一个或状态的定义
也就是说
人或者处于工作年龄
或者是已经退休
婚姻状态下
则有更复杂的一个层次的
状态机的定义
我们可以处在单身
或者是已婚状态
单身状态下
又可以是未婚 丧偶 离婚状态
通过一些和婚姻相关的
事件的发生
我们在这些状态之间发生迁移
但很明显的在这些状态图中
我们没有标志出
状态迁移的条件 事件和动作
因此 这不是一个完整的
状态图的定义
如果想要建立一个完整的状态图
需要添加迁移的条件
动作和事件
组合状态的状态迁移
根据它迁移的起点和终点的不同
它的含义是不同的
指向组合状态的边界的状态迁移
等价于指向该组合状态初态的
一个迁移
也就是说 属于该组合状态的
入口条件将要被检查
从组合状态边界
转出的迁移
等价于从该组合状态的
终态发出的迁移
也就是说
要检查该出口条件以及
执行出口动作
迁移也可以透过
组合状态的边界
直接指向组合状态里头的子状态
这样就和普通的状态迁移
是一样的
只是 去执行迁移的线上的
条件和动作
这是我们在上一节给大家介绍的
订单处理对象的
状态迁移的过程
现在我希望大家要在图中
增加一个新的状态
和相关的状态迁移
表示在任何一个订单上的产品
投递之前
都可以随时取消订单
如果我们不采用组合状态的方法
要完成刚才的任务的话
我们就需要为每一个状态
引入一条迁移
指向刚刚定义的新状态
取消订单
这会大大增加我们模型的复杂度
降低模型的可读性
而引入一个新的超级状态
也就是组合状态Active
活动订单
并在这个组合状态的边界
引出一条指向取消订单的
迁移的话
就会大大的降低这个
修改所带来的影响
使得我们的模型可读性
和清晰性依然保持
因此 可以看出引入组合状态
和超级迁移的好处
在UML状态图中
另外一个相对来说
比较高级一点的概念
就是历史状态
历史状态实际上是一个伪状态
当激活这个状态的时候
我们可以保存上一次
从组合状态中退出时候
所处的那个子状态
用H来表示
当再次进入该组合状态的时候
我们可以直接进入到这个状态
而不是再次从组合状态的
初态开始执行
H状态也可以进行进一步的延伸
定义成H*状态
H状态只记录
一层组合状态的历史
就是上一次的历史
只能回退一次
而H*状态可以记住
任何深度的组合状态的历史
可以看成是一个历史状态的堆栈
右侧给出了一个
历史状态定义的例子
比如我们将历史状态
定义到组合状态备份当中
如果上一次的备份
如果进行了一半 退出的话
下一次备份可以从
上一次备份中断的地方继续开始
这是带有历史状态定义的
课程注册过程的一个状态图
比如
一位同学在课程注册的过程中
临时退出
那么 下一次再进入该课程
注册活动的时候
我们将从上一次拟选课
终止的地方继续执行
也就是说 整个选课过程
首先要先选四门必选课
再选两门选修课
在这个过程中
我们会保存以往的历史记录
在中断的地方重新开始执行
这种机制在允许挂起的
状态机中是非常有用的
由于状态图是一个
完全形式化的模型
我们可以用工具
来支持根据状态图
生成代码的工作
比如这里是一个
对字符串进行扫描
提取字符串中
双尖括号内部的
字符串的一段逻辑
那么 我们用RationalRose
自动生成代码的话
就会获得这样的类的定义
在UML状态图中
出现的所有的事件的定义
应该和顺序图中
该对象的输入消息是一致的
状态图中应针对类图中
具有重要行为类的对象进行建模
每个事件 动作
都对应于相应类中的
一个具体的操作
状态图中每个输出消息
都对应于其它类的操作
状态图中的操作定义
应该是和类图中操作的定义
是一致的
比如右面的图中
我们给出的就是之前的
订单处理的对象
它的操作的定义
这里 操作的定义
和我们后边的定义的
状态图中的操作和动作
具有相关性
在状态图的建模过程中
我们要注意把初态
放置在左上角的位置
把终态放置在右下角的位置
便于读者导航
状态的定义如果用英文的话
是用过去时来命名的
这样做是为了反映状态的迁移
是某个事件的结果
也就是说事件出现在
迁移发生之前
因此 引用这个事件的时候
要用过去式
比如Cancelled,Closed, Scheduled
另外 警戒事件的条件之间
不能存在重叠
从一个状态出来的
相似的转移
它的警戒条件彼此之间
应该是互斥的
而且应该是尽量做到全覆盖
如果我们将X<0 X=0和X>0
这样的警戒条件放上去
那么 这个警戒条件就是互斥的
当我们定义了其中一个
迁移是X≤0
另外一个是X≥0
这样的警戒条件
由于其非互斥的情况
当X=0的时候
我们就不知道该遵循条迁移
进入哪个下一个状态
因此 状态机就变成了
非确定的行为的一个定义
另外一条建模风格
要求我们不要把警戒条件
放在初始的转移上
当警戒条件不满足的时候
我们就不能够开始
这个对象的行为
因此 是不合理的
状态图建模完成之后
我们要检查状态图中
所有的事件
是否在类图中
对本对象类的方法定义中出现
状态图中所有的动作
是否在类图中
其他对象类的定义中出现
从风格方面
每个状态的命名
是否意义明确
并且是唯一的
我们是否对行为复杂的状态
使用了组合状态
状态图中是否包括了
太多的细节
是否容易阅读
定义警戒条件的时候
是不是含义明确
会不会引入不确定性
在下面的情况下
我们不应该采用状态图建模
首先是大部分的状态迁移
都是当此状态的动作完成时
这种情况下我们应该用
活动图来建模
如果我们发现有很多来自
对象自身的出发条件的时候
这种事件
由对象自身发出的时候
这时不适合采用
状态图来定义的
因为这个实际上
就是在描述对象自身的行为
它不是状态迁移的这种场景
状态所代表的信息
和类中的属性
定义不是很一致的时候
也应该慎用状态图
-1.1 软件无处不在
--讲课视频
-1.2 软件的本质特性
--讲授视频
-1.3 软件工程的产生与发展
--讲授视频
-1.4 软件工程的基本概念
--讲授视频
-1.5 软件质量实现
--讲授视频
-1.6 业界人士谈软件工程
-测验题--作业
-讨论题
--讨论题
-作业题
--第一张 作业题
-2.1 编程过程与规范
--讲课视频
-2.2 良好的编程实践
--讲课视频
-2.3 Python集成开发环境
--讲课视频
-2.4 代码静态检查
--讲课视频
-2.5 代码性能分析
--讲课视频
-2.6 结对编程实践
--讲课视频
-2.7 刘贺谈软件工程
--讲课视频
--讨论
-测验题--作业
-作业题
--第二章 作业题
-3.1 单元测试概述
--讲课视频
-3.2 黑盒测试方法
--黑盒测试方法
-3.3 白盒测试方法
--基本概念
--代码覆盖标准
--基本路径测试
-3.4 单元测试工具
--单元测试工具
--html
-测验题--作业
-作业题
--第三章 作业题
--作业题附件
-4.1 软件过程
--讲课视频
-4.2 软件过程模型
--讲课视频
-4.3 敏捷开发过程
--讲课视频
-4.4 微软公司开发过程
--邹欣经理自我介绍
--微软开发过程之一
--微软开发过程之二
-测验题--作业
-5.1 团队组织与管理
--讲课视频
-5.2 项目沟通管理
--讲课视频
-5.3 软件项目计划
--讲课视频
-5.4 软件项目估算
--讲课视频
-测验题--作业
-讨论题
--讨论
-6.1 敏捷开发之Scrum
-- 敏捷开发之Scrum
--html
-6.2 用户故事与估算
--讲课视频
-6.3 团队协作工具Tower
-6.4 配置管理
--讲课视频
-6.5 配置管理工具Git
--讲课视频
-测验题--作业
-作业题--作业
-7.1 需求工程师
--讲课视频
-7.2 需求定义
--讲课视频
-7.3 需求的类型
--讲课视频
--讲课视频(2)
-7.4 需求工程过程
--讲课视频
-7.5 需求的主要来源
--讲课视频
-7.6 需求获取技术
--讲课视频
--讲课视频二
--讲课视频三
-7.7 撰写需求文档
--讲课视频
-测验题--作业
-讨论题
--讨论
-8.1 用例建模概念
--讲课视频
-8.2 用例建模过程
--讲课视频
-8.3 用例建模精讲
--讲课视频
-8.4 建模工具介绍
--讲课视频
-8.5 微信抢票应用案例
--讲课视频
-测验题--作业
-讨论题
--讨论
-9.1 面向对象分析
--讲课视频
-9.2 CRC卡片分拣法
--讲课视频-1
--讲课视频-2
-9.3 面向对象设计
--讲课视频-1
--讲课视频-2
-9.4 类图建模
--讲课视频-1
--讲课视频-2
-第9章 面向对象分析与设计--测验题
-讨论题
--讨论
-10.1 顺序图概念
--讲课视频
-10.2 顺序图建模
--讲课视频
-10.3 顺序图风格
--讲义视频
-10.4 状态建模
--讲课视频
-10.5 状态图
--讲课视频
-10.6 状态图精讲
--讲义视频
-测验题--作业
-讨论题
--讨论
-11.1 软件体系结构概念
--讲授视频
-11.2 软件设计原则
--讲授视频
-11.3 软件体系结构风格(一)
--讲授视频
-11.4 软件体系结构风格(二)
--讲授视频
-11.5 软件体系结构风格(三)
--讲授视频
-11.6 软件设计过程
--讲授视频
-11.7 Web系统架构设计
--讲授视频
-11.8 数据库选择策略
--讲授视频
-测验题--作业
-作业题
--html
--html
--html
-作业题--作业
-12.1 交互设计概述
--讲授视频
-12.2 交互设计目标
--讲授视频
-12.3 GUI设计原则
--讲课视频
-12.4 KLM效率模型
--Video
-12.5 Fitts定律
--讲授视频
-12.6 交互设计过程
--讲授视频
-测验题--作业
-13.1 软件测试概念
--讲课视频
-13.2 软件测试类型
--讲课视频
-13.3 软件功能测试
--讲课视频
-13.4 软件性能测试
--讲课视频
-测验题--作业
-14.1 软件部署与交付
--讲课视频
-14.2 软件演化与维护
--讲课视频
-测验题--作业
-第一部分:基础知识
-第二部分:编程与测试(选做)