目录
1、依赖(dependency)
1.1.1、绑定(bind)
1.1.2、导出(derive)
1.1.3、允许(permit)
1.1.4、实例(instanceOf)
1.1.5、实例化(instantiate)
1.1.6、幂类型(powertype)
1.1.7、精化(refine)
1.1.8、使用(use)
1.2.1、引入(import)
1.2.2、访问(access)
1.3.1、延伸(extend)
1.3.2、包含(include)
2、泛化(generalization)
2.1、完全(complete)
2.2、不完全(incomplete)
2.3、互斥(disjoint)
2.4、重叠(overlapping)
3、关联(association)
3.1、导航
3.2、可见性
3.3、限定
3.4、组合
3.5、关联类
3.6、约束
4、实现(realization)
如果正在建造一所房屋,决定各房间的布局是一项关键的任务。在某一抽象层次上,可以决定把主卧室放在主层,远离房屋的前部。随后通过普通的场景来帮助思考对这种房间布局的用法。例如,考虑从车库拿出食品。由于从车库穿过卧室走到厨房的布局是无理的,因此会拒绝这样的布局。
通过对这些基本关系和用况的构思,可以形成一个相当完整的房屋楼层布置图。然而,这还不够。如果不考虑更为复杂的关系,最终会由于设计中的一些实际缺陷而失败。
关系(relationship)是事物之间的联系。在面向对象的建模中,
4 种最重要的关系是依赖、泛化、关联和实现。在图形上,把关系画成线段,用不同种类的线段区别不同的关系。
1、依赖(dependency)
是一种使用关系,它描述了一个事物(如类SetTopController)的规约的变化可能会影响到使用它的另一个事物(如类ChannelIterator),但反之不然。在图形上,把依赖画成一条指向被依赖的事物的虚线。当要表明一个事物使用另一个事物时,就运用依赖。
应用到类图中的类和对象之间的依赖关系上的衍型:
1.1.1、绑定(bind)
表明源用给定的实际参数实例化目标模板。
当对模板类的细节建模时,要使用绑定(bind)。例如,模板容器类和这个类的实例之间的关系被模型化为绑定(bind)依赖。绑定包括一个映射到模板的形式参数的实际参数列表。
1.1.2、导出(derive)
表明可以从目标计算出源。
当对两个属性或两个关联之间的关系建模时(其中的一个是具体的,另一个是概念性的),要使用导出(derive)。例如,类 Person 可以有属性 BirthDate(具体的)和 Age(可以从BirthDate中导出,因此在类中不必另外表示)。可以用一个导出(derive)依赖表示Age和BirthDate间的关系,表明Age是从BirthDate中导出的。
1.1.3、允许(permit)
表明源对目标给予特定的可见性。
当允许一个类访问另一个类的私有特征时(例如 C++中的 friend 类),则使用允许(permit)。
1.1.4、实例(instanceOf)
表明源对象是目标类目的一个实例。一般用文本形式source :Target来表示。
1.1.5、实例化(instantiate)
表明源创建目标的实例。
可以用以上两个衍型对类/对象关系显式地建模。当对同一个图中的类和对象之间的关系建模时,或对同一个图中的类和它的元类之间的关系建模时,要使用的实例(instanceOf);然而通常还是用文本语法来表示。当要详述一个类创建另一个类的对象时,要使用实例化(instantiate)。
1.1.6、幂类型(powertype)
表明目标是源的幂类型。幂类型是一个类目,其对象都是一个给定父类的子类。
对分类其他类的类建模时,要使用幂类型(powertype),例如对数据库建模时就会发现这种情况。
1.1.7、精化(refine)
表明源比目标处于更精细的抽象程度上。
当在不同的抽象层次对代表相同概念的类建模时,要使用精化(refine)。例如,在分析时,可能要遇到类Customer,在设计时,要将它精化为更详细的类Customer,其详细的程度要达到可以交付去实现。
1.1.8、使用(use)
表明源元素的语义依赖于目标元素的公共部分的语义。
当要显式地把一个依赖标记为使用关系时,就要应用使用(use),使之有别于其他衍型提供的各式各样的依赖。
应用到包之间的依赖关系:
1.2.1、引入(import)
表明目标包中的公共内容加入到源包的公共命名空间中,好像它们在源中已经声明过似的。
1.2.2、访问(access)
表明目标包中的公共内容加入到源包的私有命名空间中。可以在源中使用这些内容的不带限定的名字,但不可以再输出它们。
当要使用在其他包中声明的元素时,就利用访问(access)和引入(import)。引入元素避免了在文本表达式中以受限全名去引用另一个包的元素。
应用用例间的依赖关系:
1.3.1、延伸(extend)
表明目标用况扩展了源用况的行为。
1.3.2、包含(include)
表明源用况在源所指定的位置上显式地合并了另一个用况的行为。
当要把源用况分解为可复用的部分时,要使用延伸(extend)和包含(include)关系(以及简单的泛化)。在对象之间的交互语境中会遇到一种衍型。
发送(send)。表明源类发送目标事件。
当对向目标对象(它可能有相关联的状态机)发送给定事件的操作(例如,在与状态转移相关的动作中就有这样的操作)建模时,要使用发送(send)。发送依赖在效果上是把若干独立的状态机结合在一起。
系统的元素组织成子系统和模型的语境:
跟踪(trace)。表明目标是源的早期开发阶段的祖先。
当对不同模型中的元素之间的关系建模时,要使用跟踪(trace)。例如,在系统的体系结构语境中,用况模型(描述功能需求)中的一个用况可能要跟踪到相关设计模型(表示实现这个用况的制品)中的一个包
2、泛化(generalization)
是一般类目(称为超类或父类)和较特殊的类目(称为子类或孩子类)之间的关系。例如,可能遇到一般类Window和它的较特殊类MultiPaneWindow。通过从子类到父类的泛化关系,子类(MultiPaneWindow)继承父类(Window)的所有结构和行为。在子类中可以增加新的结构和行为,也可以覆写父类的行为。在泛化关系中,子类的实例可以应用到父类的实例所应用的任何地方,这意味着可以用子类替代父类。
应用到泛化关系上的4个约束:
2.1、完全(complete)
表明已经在模型中给出了泛化关系中的所有子类(虽然有一些子类可能在图中省略),不允许再有更多的子类。
2.2、不完全(incomplete)
表明没有给出泛化中的所有子类(即使有一些子类可能在图中省略),允许再增加子类。
除非有别的说明,否则可以假设任何图都只描述了继承网格结构的部分视图,因此它是省略的。然而,省略与模型的完整性不同。特别地,当要明确地表示已经充分地详述了模型中的层次时(虽然没有一幅图能够显示这样的层次),要使用完全(complete)约束;当要明确地表示还没有陈述模型中层次结构的完整描述时(虽然一幅图能够显示该模型的任何事物),则使用不完全(incomplete)约束。
2.3、互斥(disjoint)
表明父类的对象最多以给定的子类中的一个子类作为类型。
例如:类Person可以特化为互斥的类Woman和Man。
2.4、重叠(overlapping)
表明父类的对象可能以给定的子类中的一个以上子类作为类型。
例如:可以把类Vehicle特化为重叠的子类LandVehicle和WaterVehicle(两栖交通工具同为二者的实例)。
3、关联(association)
是一种结构关系,它详述了一个事物的对象与另一个事物的对象相联系。
例如,类Library与类Book可能有一对多的关联,这表明每一个Book实例仅被一个Library实例所拥有。此外,给定一个Book,能够找到它所属的Library;给定一个Library,能够找到它的全部Book。在图形上,把关联画为连接相同或不同类的一条实线。当要表示结构关系时,就使用关联。
4种应用到关联上的基本修饰:关联名、关联每一端的角色、关联每一端的多重性以及聚合。
建模特性:
3.1、导航
给定两个类(如Book和Library)之间的一个简单的、未加修饰的关联,从一个类的对象能够导航到另一个类的对象。除非另有指定,否则关联的导航是双向的。然而,有些情况要限制导航是单向的。
如图所示,当对操作系统的服务建模时,会发现在对象 User 和Password 之间有一个关联。给定一个 User,需要找到对应的对象 Password,但给定一个Password,就不需要能识别相应的 User。通过用一个指示走向的单向箭头修饰关联,可以显式地描述导航的方向。
3.2、可见性
给定两个类之间的关联,除非另有显式的导航声明所规定的限制,否则一个类的对象能够看见并导航到另一个类的对象。然而,在有些情况下要限制关联外部的对象通过关联访问相关对象的可见性。
如图所示,在UserGroup和User之间有一个关联,在User和Password之间有另一个关联。给定一个对象User,可能识别出它的相应的对象Password。然而,对于User来说Password是私有的(-key),因而从外部来说它应该是不可访问的(当然,除非User通过一些公共操作显式地暴露了对 Password的访问)。
如图所示,给定对象 UserGroup,可以导航到它的对象 User(反之亦然),但不能进一步看到对象 User 的对象 Password,因为Password是User私有的。
在UML中,像处理类的特征那样,通过对角色名添加可见性符号,可以在3个级别上描述关联端点的可见性。除非有别的注解,否则角色的可见性是公共的。
私有的可见性表明,位于关联该端的对象对关联外部的任何对象来说都是不可访问的;
保护的可见性表明,位于关联该端的对象对关联外部除了另一端的子孙之外的任何对象来说都是不可访问的。
包的可见性表明,在同一包中声明的类能够看见给定的元素,因此对关联端点不适用。
3.3、限定
在关联的语境中,最常见的一种建模的惯用法是查找。给定关联一端的对象,如何识别另一端的对象或对象集?
例如,考虑对一个制造厂的工作台的建模问题,在工作台上对返回的工件进行修理。
如图所示,要对类WorkDesk和类ReturnedItem之间的关联建模。
在WorkDesk的语境中应该有一个标识具体的ReturnedItem的jobID。
在这个意义上,jobID是关联的属性,不是 ReturnedItem 的特征,这是因为工件没有诸如修理或加工这样的信息。然后,给定一个 WorkDesk对象并给定 jobID一个值,就可以找到0 或1个 ReturnedItem的对象。在UML中,用限定符(qualifier)来对这样的用法建模,该限定符是一个关联的属性,它的值通过一个关联划分了与一个对象相关的对象的子集合(通常是单个对象)。
如图所示,把限定符画成与关联的一端相连的小矩形,并把属性放于小矩形中。源对象连同限定符的属性值确定了目标对象(若目标端的多重性最多为1)或对象集合(若目标端的多重性为多)。
3.4、组合
聚合是一种有较深语义的简单概念。简单聚合完全是概念性的,只不过是要区分整体与部分。简单聚合既没有改变整体与部分之间跨越关联的导航含义,也不与整体和部分的生命周期相关。
组合是聚合的一种形式,它具有强的拥有关系,而且整体与部分的生命周期是一致的。带有非确定多重性的部分可以在组合物自身之后创建,但一旦创建,它们就同生共死。这样的部分也可以在组合物死亡之前显式地撤销。
一个对象在一个时间内只能是一个组合的一部分。例如,在窗口系统中,一个Frame只属于一个Window。相比之下,在简单聚合中,一个部分可以由几个整体共享。例如,在房屋模型中,Wall可以是一个或多个Room对象的公有部分。
在组合式聚合中,整体负责对它的各个部分的处置,这意味着整体必须管理它的部分的创建与撤销。例如,当在窗口系统中创建一个Frame时,必须把它附加到一个它所归属的Window。类似地,当撤销一个Window时,Window对象必须依次撤销它的Frame部分。
组合确实只是一种特殊的关联,通过在整体端用一个实心菱形箭头所修饰的简单关联来表示。
3.5、关联类
在两个类之间的关联中,关联本身可以有特性。
例如,在Company和Person之间的雇主/雇员关系中,有一个描述该关系特性的Job,它只应用于一对Company与Person。用从Company到Job的关联和从Job到Person的关联对这种情况建模是不适当的。这没有把Job的特定实例和特定的一对Company与Person联系在一起。
在UML中,把这种情况建模为关联类,关联类是一种既具有关联特性又具有类特性的建模元素。可以把关联类看成是具有类特性的关联,或者看成具有关联特性的类。
把关联类画成一个类符号,并把它用一条虚线连接到相应的关联上
3.6、约束
关联的这些简单的和高级的特性足以满足所遇到的大多数的结构关系。然而,如果要详述其含义的细微差别,
UML定义了5种可以用于关联关系的约束。
首先,可以描述在关联一端的对象(多重性要大于1)是有序还是无序。
(1)有序(ordered)。表示关联一端的对象集是显式有序的。
例如,在User/Password关联中,与User相关联的Password可以按最近被使用的时间排序,并被标明为ordered。如果没有这个关键字,对象就是无序的。
其次,可以描述在关联一端的对象是唯一的,即它们形成了集合,或者是不唯一的,即它们形成了袋(bag)。
(2)集合(set)。对象唯一,不可以重复。
(3)袋(bag)。对象不唯一,可以重复。
(4)有序集合(order set)。对象唯一且有序。
(5)表(list)或序列(sequence)。对象有序但可以重复。
最后,还有一种约束限制了关联实例的可变性。
(6)只读(readonly)。一旦从关联的另一端的对象添加了一个链,就不可以修改或删除。在没有这种约束的情况下,默认可变性为无约束。
4、实现(realization)
是类目之间的语义关系,在该关系中一个类目描述了由另一个类目保证实现的合约。在图形上,把实现画成一条带有空心三角箭头的虚线并指向描述合约的那个类目。
在大多数情况下,要用实现来描述接口和(为其提供操作或服务的)类或构件之间的关系。
接口是一组操作的集合,其中的每个操作用于描述类或构件的一个服务。因此,接口描述了类或构件必须实现的合约。一个接口可以由多个这样的类或构件实现,一个类或构件也可以实现多个接口。或许关于接口的最有趣的事情是它允许把合约的描述(接口本身)与实现(由类或构件完成)分离开来。此外,接口跨越了系统体系结构的逻辑部分和物理部分。
如图所示,在系统设计视图中的类(如订单登记系统中的AccountBusinessRules)可以实现一个给定的接口(如 IRuleAgent)。
同一个接口(IRuleAgent)也可以由系统实现视图中的构件(如acctrule.dll)来实现。
用两种方式来表示实现:
一种是规范方式(用衍型interface以及一条带有空心三角箭头的有向虚线);
另一种是省略方式(用接口的棒棒糖表示法来表示供接口)。
也可以用实现来描述用况与实现该用况的协作之间的关系,如下图所示。在这种情况下,几乎总是要采用从实现出发的虚线箭头形式。