最近都在学习软件设计方面的实践,就打算好好学习uml方面相关的知识,就重新整理下uml一些核心元素的概念的。
版型
版型,在大象UML学习一书中提到了这个词。这个词是对一个UML元素基础定义的拓展,举个例子,比如在java当中,我们把接口、边界类、实体类、抽象类等都是类的版型。这就是版型。uml中几乎每一个元模型都有很多版型,例如用例有"业务用例"、"业务用例实现"等版型。
版型只是UML的一种拓展手段,本身不会涉及思想和方法,而是我们在建模的不同阶段,为了区分视图的不同观点,会采用不同的图来表示,例如:"业务用例"、"业务用例实现"就是专门应用在业务建模场合的,重要的不是业务用例的版型长什么样,而是理解当用例用于获取捕获需求时,用例会有一些特别的意义。
参与者
参与者在建模过程中处于核心地位的,是在系统之外与系统交互的某人或者某物。
如何确定一个系统的参与者
举个场景: 小王到银行去开户,向大厅经理询问了办理手续,填写了表单,交给柜台职员,拿到了银行存折,在这个场景中,谁是参与者?
确定参与者需要先确定系统的边界,确定了边界,就可以接着去确定谁是参与者。怎么确定边界呢?可以参考下面两个问题。
- 确定谁对系统有明确的要求和目标并且主动发出动作?
- 该系统是为谁服务的?
看上面的例子,我们看第一个问题,首先,小王有着明确的目标:开户,并且主动发出开户动作。2. 系统运作的结果是给小王提供开户的服务。所在可以确定小王是参与者,而大厅经理和职员都不满足条件,在小王没有主动发出申请,他们不会动作,所以我们可以确定小王是参与者,然后明确了系统的边界了,大厅经理和职员都是边界以内的。
参与者是可以是非人的,比如计算机系统,一个计时器,一个传感器或JMS信息。
参与者的版型
- 业务主角: 特别用于定义业务的参与者
- 业务工人:被动的参与了业务的参与者。
- 涉众: 涉众是与要建设这个系统有利益相关的一切人和事。比如投资方等等
4.用户: 用户是指系统的使用者,用户是参与者的代表或者说是参与者的实例或代理,并非所有的参与者都是用户,但是一个用户可以代理多个参与者。
5.角色: 角色是参与者的职责。
概括: 参与者是涉众的代表,它代表涉众对系统利益的要求,并向系统题出建设要求,参与者通过代理给其他用户或者将自身实例化成用户来使用系统,参与者的职责可以用角色来归纳,用户呗指定扮演哪个角色或者哪些角色因此来获得参与者的职责。
用例
用例定义了一组用例实例,其中每个实例都是系统所执行的一系列操作,这些操作生成特定的主角可以观测的值。
通俗来讲就是,一个用例就是与参与者交互的,并且给参与者提供可以观测的有意义的一系列活动的集合。所谓用例就是要完成一件事,需要做一系列的活动,而做这件事,可以有很多不同的办法和步骤,也可能会遇到各种各样意外的情况,因此这件事由许多不同的情况的集合构成,在UML称为用例场景,一个场景就是一个用例的实例。
一个完整的用例定义由参与者、前置条件、场景、后置条件构成
用例的特征
- 相对独立,不需要与其他用例交互来完成参与者的目的。
- 用户的执行结果对参与者来说是可以观测和有意义的。
3.用例必须由一个参与者发起。 - 重点: 一个用例就是一个需求单元、分析单元、设计单元、开发单元、测试单元甚至部署单元。
用例的粒度
粒度的概念相信不用再解释了,一个用例的粒度大小如何确定才是实践中比较重要的,可以分享的经验是,在项目过程中根据阶段的不同,可以使用不用的粒度。
在业务建模阶段,用例的粒度以每个用例能够说明一件完整的事情为宜,既一个用例可以描述一些完整的业务流程。
在业务分析阶段,即概念建模阶段,用例的粒度以每个用例能描述一个完整的事件流为宜。可以理解为一个用例面熟一项完整的业务中的一个步骤。
在系统建模阶段,用例视角是针对计算机的,因此用例的粒度以一个用例能够描述操作者与计算机的一次完整交互为宜,例如填写申请单、审核申请单、派发任务等等。
粒度的选择主要还是因为边界认定不同而产生的,如果对选择粒度感到问难,可以看自己是否选择了一个正确的边界,或者越过了这个边界。
例子:用例的版型
1.业务用例
专门用于需求阶段的业务建模,在为业务领域建模时应当使用这种版型。业务用例专门用于业务建模,在需求阶段的业务建模,就是没有计算机参与的,目前客观存在的业务领域。它的参与者是业务主角。范围是业务范围,而不是系统范围,所以不需要计算机参与。
2.概念用例
概念用例用于概念建模,一般很少使用。
3.系统用例
系统用例没有定义,就是我们正常所说的用例。系统用例就是用来定义系统范围、获取功能性需求的,因此系统用例的含义就是,系统用例是软件系统开发的全部范围。
4.边界
边界本质上是面向对象方法的一个很重要的概念,与封装的概念师出同源,面向对象里,任何对象都有边界,外界只能通过边界来认识对象。对有形的边界,比如电视剧,边界就是屏幕面板,但对于无形的,比如系统边界,倒不如说是需求的集合边界,确定好需求,才能确定边界。
5.业务实体
业务实体就是代表业务角色执行业务用例时所处理的或者使用的“事、物”,一个业务实体经常代表某个或者许多业务用例实例有价值的事物。
业务实体一般来自现实世界,我们在建模时,一定能找到与它对应的事物。举个例子: 饭店的业务实体有菜单和饮料饭菜等,在机场,机票和登机牌就是业务实体,业务实体一定是在分析业务流程中发现的,而业务流程实际上就是业务用例场景,最后业务实体其实就是类的一个版型,具有类的所有属性。
6.包
包是UML中非常实用的一个元素,主要作用就是容纳并未其他元素分类,它可以容纳任何UML元素,比如用例,业务实体,、类图等,也包括了子包,在Rose可以看到有三个默认的顶级包,Use Case View、Logic View和Component View,在其下可以按需要建立无限层次的分包。
关于分包,好像是随意的,但其实不然,UML对于分包是有一些指导原则的,分包的好坏由包之间的依赖关系来评判,事实上,在UML中,包之间关系只有依赖关系,好的分包需要高内聚低耦合。
7.分析类
分析类用于获取系统中的职责簇,他们代表系统中的原型类,是系统必须处理的主要抽象概念的“第一道关口”,分析类还可以产生系统设计的主要抽象===系统的射击类和子系统。
分析类是业务需求向系统设计转化过程中最主要的元素,他们在高层次抽象出系统实现业务需求的原因,业务需求通过分析类逻辑化。这么说很模糊,我们看下分析类的分类就清楚了。
分析类分类
- 边界类
边界类是一种用于对系统外部环境与其内部运作之间进行建模的类,这种交互包括转换事件,并记录系统表示方式比如接口中的变更,在从需求向实现转换的过程中,任何有交互的两个关键对象,都需要考虑建立边界类。
这么说很模糊,对现实世界中,边界类的实例可以是窗口、通信协议、传感器等,在计算机中,可以是一个消息中间件,一个驱动程序,一组对象接口甚至任意一个类,总之,无论是现实世界还是计算机世界,当我们打算对对象A以及对象B的交互进行建模时,边界类都可以充当这一个载体。
看一些需要边界类的场景:
- 参与者与用例之间
例如:参与者通过一个网页,一组窗口来使用用例的功能。 - 用例与用例之间如果有交互,应当建立边界类。
一个用例要访问另一个用例,直接访问用例对象是不好的结构,这样将导致紧耦合的发生,而边界类可以解耦,类似门面模式,实现时,可以演化为一组API,JMS或者代理类。 - 用例与系统之外的非人对象,比如第三方支付系统,当建立边界类。
这正常是因为异构系统、异构数据、访问权限等,具体实现时,要演化为中介和通信协议。中介例如网关、通信中间件、代理服务器、SOA这种,通信协议就是Http协议等。 - 相关联的对象有明显的独立性要求
最后,从架构角度来讲,边界类一位于展示层。
边界类的特征:
可以提高系统可用性,解耦。
- 控制类
对于一个或几个用例所特有的控制行为进行建模,控制对象通常控制其他对象,因此他们的行为具有协调性质。从架构角度上,控制类主要位于业务逻辑层,控制类的获取对架构设计中的业务逻辑层有着重要的指导意义。
3.实体类
就是业务实体,javaBean对象,通常都是永久性,所具有的属性和关系是长期需要的,有时甚至在系统的整个生命期都需要。
在设计阶段,实体类代表了Pojo类,一系列pojo类,从架构角度上,实体类主要位于数据持久层。
分析类的三高
分析类的抽象层次有三高的特点。
高于设计实现,高于语言实现,高于实现方式
8. 设计类
设计类是系统实施一个或者多个的抽象,设计类所应对应的对象取决于实施语言,设计类用于设计模型中,它直接使用与编程语言相同的语言来描述。对于java语言中的接口。设计类由类型、属性和方法构成。关系
在UML中关系是非常重要的概念,它抽象出对象之间的联系,让对象构成某个特定的结构。在UML中关系一共有9种,下面将一一介绍:
- 关联关系
使用一条直线表示,描述不同类的对象之间的关系,是一种静态关系,在代码中以实例变量的成员实现。
- 依赖关系
使用带箭头的虚线表示,A-------> B,A依赖于B。描述对象运行时会用到另一个对象的关系,是一种临时性关系,只在运行时产生。一般而言,依赖关系在代码中以类构造方法、类方法等的传入参数。与关联关系不同,被依赖对象,会导致依赖对象的属性或者行为的修改。
- 拓展关系
特别用于在用例模型中说明向基本用例中的某个拓展点插入拓展用例,
一般来水,拓展用例是带有抽象属性的,代表用例场景中的某个“支流”,由特定的拓展点触发而启动,所以严格来说,拓展用例,应用在概念模型中,通过分析业务用例场景抽象出关键的可选核心业务而形成拓展用例。
与包含关系不同的是,拓展用例是可选的,而不是必须的,没有这个用例,基本用例也是完整的。举个例子: 在接电话过程中,另外一个电话进来了,我们可以保留当前电话,接听另一个也可以不保留当前电话,是否保留取决于个人的决定,而不是必须的。
- 包含关系
特别用于用例模型,说明在执行基本用例实例的过程中插入的行为段。
与拓展用例类似,但是他是必须的,可以代表在各自不同基本用例中复用的行为。
举个例子: 比如你去银行办理各种业务,无论取钱、转账、存钱,都必须验证账号和密码,因此可以将这部分的行为抽取出来,形成包含用例。
- 实现关系
,特别用于在用例模型中连接用例和用例实现,说明基本用例的一个实现方式。
基本用例描绘了一个业务目标,但是该目标有多种实现方式,每种途径都对应一种用例实现来表示,那用例实现与基本用例就构成了实现关系。换句话说,每个实现都实现了基本用例的业务目标。
比如缴纳电话费,此时有三种用例实现,此时就是三种实现关系。
- 精化关系
,用于用例模型,一个基本用例可以分解出许多更小的精化用例,可以更细致的展示用例的核心业务。
与泛化关系不同的是,精化关系表示基本对象分解更精细的子对象,子对象没有增加、减少、改变基本对象的行为和属性,但在泛化关系中,基本对象被泛化成子对象后,子对象继承了基本对象的所有特征,并且子对象可以添加、改变基本对象的行为和属性。
还有精化只用于建模,而泛化等同于实现语言中的继承。
-
泛化关系
可以用于建模的任意一个阶段,说明两个对象之间的继承关系,这个应该都很熟悉了。
-
聚合关系
聚合关系主要作用在类图,用于表示实体对象之间的关系,表达整体由部分构成的语义,比如一个部门由多个员工构成。与组合关系不同的是,聚合的整体和部分的不是强依赖的,整体不存在了,部分依然可以存在。
-
组合关系
表示A组成B或者B由A组成。在Rose中没有采用这种方式,而是采用带箭头的空心菱形。也是用于类图,跟聚合区别是,如果整体不存在了,部分也会消亡。