刚才呢是,我们介绍的是一些复杂的顺序图。
顺序图是一种特殊的 呃,这个交互图。
但在 UML中还有其他的一些交互图,我们 简单的给大家看一下。
第一个就是通讯图。
通讯图呢实际上是由 UML1 中的这个 结构图来过渡过来的。
它的一个特点呢就是既描述静态结构,又描述动态行为, 把静态结构和动态行为,二者结合到一张图里面去。
它 类似于,猛一看好像是一种这个类图,或对象图这种架构。
但是在这个对象和对象之间的这个静态的这个关联关系,或者说是
依赖关系上呢,又给它 描述上一些这个动态的一些发送的一些消息及消息与交互序列。
但是它是交互序列只能是用一种标号儿的方式来表示时间的先后顺序以及这个
因果上的已经,这个激发关系,所以它不如这个
这个顺序图中描述的这个消息的这个交互序列显得直观。
但是呢它的好处呢就是说,它加上了一些 动态的,或者说静态的行为,将静态的结构和动态的行为结合起来,
便于在,放到一张图上,便于呢这个 特别是在程序设计的后期啊,便于。
这样呢 这张图基本上跟程序的功能是很像的,因为程序包括数据结构和算法,所以 这个里面也是类似。
所以,但是呢 这个用处呢也远远没有顺序图,目前来看没有顺序图 用的那个广泛。
所以呢在 UML2 中呢其实把它有所削弱,它不像这个 UML1 中那么复杂了。
这个交互概要图呢,实际上是可以给这个用户或者说建模者一种
非常清晰的一种视角来描述一些复杂的组合到一块儿的一些交互序列。
当然用我们刚才介绍的组合交互片段这种方式,来把一些小的交互片段组合成大的交互片段也是 可以的。
但是那种方式组合起来呢,不能给人一种非常直接的,或者是鸟瞰的一种感觉。
而这个交互概要图呢恰恰是可以
非常清晰的给你一种概览的一种,一种这个视角,是吧?
直接看那个第一个层次好像就是一种活动图,这个一个节点一个节点。
但是你深入到每一个节点里边看呢,每一个节点都是一些什么呢?交互。
这样的话呢 可以非常清晰,给人一种非常清晰的一种感觉,可以把一些小的一些交互呢,
把它们,借助于这个活动图中的一些流程, 然后呢把它们组合成一个更大的一些交互。
这个相对于 那种那个,刚才我们讲的那种方式呢直观,更加直观。
但是呢这个 详细,更详细的描述呢我们还得用 那个前面讲的那个方式。
这是一种。
还有就是,这是这个我们这个举的一个例子,就是交互概要图, 一个复杂的一个交互概要图。
还有时序图 timing, timing 主要就是用来描述一些,呃
对时间非常在意的,或者说一些时序性要求非常高的一些系统。
它的一个特点呢就是,它的横坐标是一些时间跨度, 它的纵坐标呢是对象。
然后对象和对象之间发送消息呢, 实际上主要是通过一些线形图来描述对象状态,
由于对象状态的跳变导致对象可能会发送一些消息, 然后呢这个借助于这个消息然后实现另外一个对象的状态的跳变。
并且它在这个地方呢可以 描述出一些时间跨度,这就是它的这个,时序图的一个概念。
这是更完整的例子,这里是两个对象, 它们之间,每个对象之间这个消息,这个状态在不断的变化,
变化的时候呢会导致另外一个,向另外一个对象发送消息,导致这个状态不一样, 消息变化。
现实生活中这个最典型的这个可以用时序图来描述的 这个例子就是我们那个弹琴的那个琴谱。
那是一个既可以用 五线谱啊,简谱来描述,也可以用时序图来描述,这个效果是一样的。
因为我们那儿里边儿呢 不仅要注意这个每一个这个状态,而且要注意什么呢?
它的这个每一个音的这个,这个声值,声的这个 长度,发声的一个长度,所以跟这个很像。
但是它最主要的用处呢还是在
这个一些嵌入式,实时性能力要求非常强的一些系统中,肯定要。
对于这种 这个对象和对象之间啊,传递消息,呃,这种 对于这个延迟有很大的一些
这个,非常重要的这种情况下来描述这种这个,用时序图来描述。
这是我们给出的一个这个 UML 时序图的一个例子。
这个这样呢我们基本上呢这个
本周的这个知识都介绍了,下面我们通过一个完整的例子来介绍一下,这又是一个,另外一个
综合的知识点:就是我们如何将这个前两周介绍的 use case
图,类图 和顺序图之间,给它协调起来,并且用顺序图来启发我们
进一步的识别 OOA 中的类图中的类 和属性以及关系。
这样的话,它们之间是一个相互作用的一个 方式。
这个呢我们看一下这个例子。
这个例子实际上是一个科研 这个项目的一个申报和审批系统。
所有的这个使用者都必须登录,然后呢政府人员,实际上就是可以这个,
就是政府资助的项目啊,为政府资助的项目提供 一些项目信息,包括项目名称啊、
项目类型啊、 资助经费、 项目要求。
申请者呢,这个通过这个 系统获取到了这些信息,并且呢
根据信息我填写,在线填写项目申请书。
这申请书里面有什么项目名称啊,项目类型啊, 资助经费啊,什么意义啊,内容等等。
然后呢这些到了这个政府部门之后呢,这个政府部门的人员
呢在收到申请书之后呢,先对申请书进行编号,然后呢 再对格式进行审查。
若不符合这个规定要求呢, 就可以将申请书视为无效。
如果 通过初审了,那么呢还将这个
申请书发给五个专家,然后呢进行评分儿, 形成这个项目评议书。
评议书 这里面而呢有一些信息,比如说编号儿啊、 项目名称啊、 项目类型啊、 评分儿 的分数、 评价等等。
然后呢交给这个政府人员。
政府人员在收到这个消息,这些评议书之后呢, 对分数进行汇总,全加或者平均,然后呢再根据总分儿进行筛选,
选择出,指定需要资助的项目, 形成资助通知书发给申请人。
现在呢我们做一个小的案例, 把这个案例,这个小的例子。
这个例子呢实际上是从需求分析开始, 然后由需求分析我们复习一下前两周的内容,然后
我们再把本周学到的顺序图结合进来,然后再看一下
它们三者是如何很好的良性互动的,相互启发,相互作用,最后呢 最后都完整起来。
首先呢这个 use case 图我们 就不用多说了,这个是一个非常简单的 use case 图。
在画的过程中呢 所有的参与者全部都是人员,所有的这些每个人做什么事情呢,实际上是对刚才我们讲的那个-
需求的一个梳理。
然后在这个基础上呢我们识别出来一个类的草图。
这个类的草图 实际上呢全部都是问题域的方式来描述的,把刚才里边的一些
人员、 参与者,以及在这个过程中,问题域中呢有哪些的一些
对象,类识别出来,每个类有哪些关系以及属性,都识别出来。
接下来呢我们再建立这个顺序图,把所有的这个 功能点都描述清楚。
这里我们这个主要是 用一个顺序图来描述了一个比较大的,或者说比较完整的一个流程,是经过
当然也是一部分了,是吧?就是在这个
从这个政府人员进行初审的时候,一直到最后发送资助通知书整个过程。
在这个过程中我们可以看到用顺序图可以非常清晰的描述这个 整个流程的过程,并且呢在这个过程中我们可以看到这个
消息在每个对象之间啊进行传递。
这里呢我们全部都是按照一种这个顺序 系统的这种模式来进行建模儿的,这就足够了。
所以呢这个 这里边儿呢分别是查看这个,
进行初审,然后呢这个查看,这个查看这个 项目申请书,这个这是初审的工作。
初审完毕之后呢 这个对于符合要求的申请书,发给专家。
发给专家,专家在接到这个消息之后呢, 进行查看申请书,并且产生一个什么呢?项目评议书。
进行这个提交,之后呢由工作人员对这些专家的这些评议进行汇总
和审查,累加,最后填写总分,最后决定整个这个过程是非常清晰的。
在这个过程中呢 实际上这个我们可以看出
所有的这些
用于它是个顺序系统,所以这里不涉及到一些 异步信号,所以呢全部,消息传递全部都是方法调用
因此呢,这里需要注意的就是什么呢
所有的这些方法,如果说一个对象向另外一个对象发送消息,所有的这些
这些方法,这个 一旦你向,我们举一个例子,比如说这个
政府人员向专家发送一个消息要求评审,那么专家的这个
这个类里边就应该有一个评审的这么一个
一个方,一个操作,这样的话 就实现,所以这就体现了这个
use case、 类图和顺序图之间的一种 协调,它们之间呢,我们借助于这个,实际上最初
我们的类图可能没有这么完善,借助于这个顺序图我们可以
这个不断的检查我们的类图,如果类图中没有这个操作,需要向这个类发送一个
方法,但是这个时候类图中没有,这时候需要填写,啊,需要在这个
顺序图中填写并且把它映射到我们这里的类图中去 另外呢,如果说是在这个过程中
有一些关系,是吧,它既然向它发送消息了,它们之间必须建立一个关联关系,那这个
在以前类中没有关联关系,现在我们呢就需要这个 识别出一个关联关系来,这样等等很多的一些
类图借助于顺序图可以使,用 顺序图重新地描述一遍 use case ,可以使得我们
这个把这个类图,先前做的类图呢更加完善,所以它们三者呢是一个 相互协调的一个关系。
总结一点就是说这个 比如这个 use
case 可以 帮助我们产生类图,但是呢
在产生完一个类图之后呢,我们可以再把这个类图反作用到 use
case 用白盒的视角来描述这个业务逻辑,但是这个白盒视角就是借助于顺序图
通过顺序图呢又帮助我们验证了这个类图到底是不是
正确,如果不正确这块我们可以添加 借助一些工具呢,它实际上可以很好的实现。
我在这个 顺序图中添加了一个消息之后呢在,它可以自动的不需要人手动的
把你过渡,把这个消息过渡到类图中的一个方法调用啊,它这个自动,比如说 Spark 就可以做到这一点。
好, 这个这是一个简单的一个例子,它用到的,没有用到太多复杂的一些组合交互片段的例子
下面呢就是我们前边,前期讲到的这个对一个小白兔正吃胡萝卜的这个
被猎人击中的这个场景进行分析。
我们看一个同学做的 这个有一些错误,我们能帮他找出来吗?
这个比如说这个,当时这个同学呢当然他是用 这个 uml2
中的复杂的组合交互片段来看 他是一个选择,首先是无子弹的时候就吃,有子弹的时候呢
就这个倒下,猛一看好像很对,但仔细一分析结合我们刚才讲到的一些内容他就不对了,是吧- ,为什么呢?就是因为
首先,语法错误,这个,option 这是一个
具有,这个操作符只允许有一个操作数 那就是说他这个分区啊必须不能有这个虚线间隔这个分区
只能有一个,所以他这用错了这个操作符,应该是用这个 out,
这样的话呢就可以实现一种条件,所以 第一个错误就找到了。
第二个错误呢,也很明显 猎人和小白兔之间呢它分别代表一个主动对象,因此它们的生命线
是自始至终全部都是激活或者是执行的
它们都封装一个线程,如果说转换成软件系统的话。
所以这是第二个错误 第三个错误呢,就更大一些了,就是说这个
这个子弹这个东西,作为一个消息传 递的时候,它实际上是个异步消息,但是这里给它建立为同步消息
第四个是个综合的,就是说按照这个图的整个这个结构来说
它根本不可能达到我们这个
需求的要求,为什么呢?因为这是个死循环,小白兔在这一直吃胡萝卜 它一旦进入到这个 loop
里边去,那它就一直吃了 它出不来了,也没有一种中断机制或者控制机制啊把它从吃胡萝卜的状态
转换出来,然后让它这个中弹倒下 这些,所有的这些有子弹的这种情况根本是
形同虚设,因为它一旦进入这儿之后,从这个图上来看呢 它就在这一直走一直吃,来了子弹不会,没有任何的处理结果
机制,所以这种是非常错误,一共有四处错误。
这个那么我们如何
解决这个问题呢?好,那可以有很多种方式,第一种方式呢我们用这个这种复杂的一种
这个稍微复杂一点的一个相当于对刚才那个组合交互片段的综合运用
首先我们更正了这猎人是一个主动对象,小白兔呢我们为了便于这个
对我们这个中断,是吧,对我们把这个小白兔分成两个主动对象
一个叫小白兔监守对象,一个叫小白兔的工作对象 这样的话呢,这个子弹是一个什么呢?异步消息 建立为异步消息了。
这个猎人、 小白兔 之间,小白兔监守线程之间,它们三个实际上由于它们封装了
各封装一个线程,所以呢这个并发区呀它有三个
操作,这个并发操作数它有三个操作符
组合交互片段这个由这个并发 所引导这个操作符它有三个操作数
这三个操作数必须分别代表猎人这个线程,小白兔监守对象的线程和小白兔工作对象 的线程。
小白兔工作对象实际上在这闷头吃是可以的,但是我们注意这里边有一个条件
就是它有一个,设置了一个变量,workingflag 等于 1 的时候能吃 如果要
flag 等于 0 的话,你就要跳出这个循环 另外呢这个小白兔监守线程对象,它实际上是负责在
外部这个检测 一下外部对象是否向我这个当前的这个对象发送消息
那它不断地在循环,不断地在检查有没有子弹来 如果有子弹的话,那么呢
这是一个选择,是吧,如果没子弹了,还是在不断的检查,如果有子弹就执行这个,执行 到这个
option 里边,然后这时候呢首先要将 workingflag
置为 0 ,同时呢 停止这个线程
因为线程和线程之间发送消息,可以用异步的方式来进行 实现,就是它可以用一种这个
比如说最简单的方式就是给它发送一个 它们共享变量也是一种异步消息,这个当然还有其他的一种方式
这个首先工作区的,workingflag 置为 0 了,然后呢
这由于置为0 ,它就停下来了,这边就是,一看它是
只有当 1 的时候,它才不断的循环,如果它 0
的话,它这个循环就停下来 循环停下来之后并不代表着工作线程就在那
停着,所以我这呢可以向它发送一个停止的这个 异步消息让这个工作线程也停下来,这样的话呢这个小白兔呢
向自己,监守线程向自己发送一个消息让它倒下,并且呢将自己删除掉 这就可以了,是吧。
然后这个子弹 是一个异步消息,为什么是个异步消息呢?就是因为
它是从猎人通过扣动扳机激发的这么一个子弹这个消息
这个子弹这个消息呢这个实际上呢在 发给这个小白兔监守对象时候,小白兔监守对象呢
这个并没有做好准备接收这个消息,因此呢,它是一个
异步消息,这个它实际上是
小白兔监守线程实际上在那不断的检查子弹
但是呢它们之间呢,是吧,不是那种,跟那种这个
它因为它是两个不同的对象,主动对象之间,因此呢 它们之间的这种,尽管它是在不断地检查对象
但是呢,不断地检查子弹,但是呢跟我们那个 一个主动对象向一个被动对象发送消息,那个机制是不同的,它是
实际上是将子弹放在它的缓冲区里边,或者它的消息堆里边,它不断地去检查这个 缓冲区,这样的话,尽管是同步消息,尽管是异步消息呢
它也可以保证它,因为我们这有两个线程 所以也可以保证这个小白兔在接受到这个子弹之后马上
停止吃胡萝卜并且倒地死去,这样的话呢 由此我们看到,同步消息和异步消息与它这个
接到消息的响应快慢实际上是没有关系的,不管是同步消息还是异步消息都可以实现
接到这个消息之后马上执行,这里我们用两个线程的方式也可以 实现。
另外呢还有一种方式,一个线程可不可以?也可以,是吧 当然这个,这就是这个猎人
和小白兔各占一个线程,它们之间呢是用一个 组合交互片段,这有标注,并发操作符来表示。
猎人激发子弹,子弹也是个异步消息 但是这个异步消息到这个小白兔这里呢,这个刚,上边
这接受机制不太一样,因为小白兔这是个中断,是吧 小白兔呢是个循环,不断地吃胡萝卜,但是呢
这个它在吃胡萝卜的间隙,或者说
这个,在这个查,我们察觉不到的这种非常快的一个时间内
插入很小的一个中断,中断这么一个小的一个小程序
中断就是比如说它吃一口胡萝卜就检查一个,当然没有,时间跨度没这么大,它可能是很
非常瞬间,这个,反正它留出了一个余地
就是说,我这,在这个吃胡萝卜和这个检查子弹是一个线程,但是呢
这个,这个线程进行了分时,大部分的时间,99% 的时间内是
吃胡萝卜,还有 1% 的这个时间内呢是检查子弹,这样的话呢两不耽误 是吧,稍微一检查,没有的话马上吃,有的话,就再做
自己这个中弹以后的事情,这样的话呢,这个 在这个
检查子弹的时候,这个就是说吃胡萝卜时候呢进行这个中断,这个检查子弹 啊,检查子弹。
检查子弹的时候如果说是有子弹的时候,进行了中断
如果说有子弹,假设没有子弹的话呢,这个还是在 在这个跳出这个
break 了, break 之后呢还是在这个循环里边,还在吃
如果说是有子弹的话呢,这时候呢就要倒下,并且删除自己,这样的话就 这个退出循环。
这样的话也是可以执行这个东西
所以呢,由这个刚,可以看出用这个顺序图可以描述非常复杂的
这个并发性的或者说一些非常复杂的业务逻辑,但是呢
这些如果说是本身就涉及到事件驱动这些行为
如果用状态图描述这种行为的时候,那就更简单了,这个用顺序图描述这些行为呢
反而呢显得非常复杂,非常这个
冗长,这个非常麻烦,所以这个我们可以
下周呢我们这个可以看,相同这个问题呢用状态图如何非常 简单的描述。
好,这是我们用到的一些参考文献
好,本周我们就讲到这儿,谢谢大家!