UML参考手册
第三部分 参 考 资 料
第13章 术 语 大 全
75.构件(component)
构件是指系统中可替换的物理部分,系统封装了实现以及提供了一组接口的实现。
语义
构件是指系统中的一个物理实现片段,包括软件代码(源代码,二进制代码,可执行代码)或者相应成分,例如脚本或命令行文件。有些构件带有身份标识,并有物理实体,包括运行时的对象,文档,数据库等。构件只在实现域中存在--它们是计算机的物理组成部分,可以与其他构件相连,由类似构件替换,移动,获得等等。模型可以表示构件间的依赖关系。例如,编译器和运行时的依赖关系,或者人类组织中的信息依赖关系。
一个构件实例可用于表示运行时存在的实现单元,包括它们在实例结点中的定位。
构件有两个特怔。它们封装了实现系统功能的代码和某些构成系统状态的实例对象。因为它们的实例含有身份和状态,我们称后者为有身份的构件。
代码特怔。 构件包含了类或者其他元素的实现代码(代码广泛采用和包括脚本,超文本结构,以及其他可执行描述形式)。源代码构件是指类实现的源代码封装包。某些语言(c++)将声明文件与方法文件分开,但它们都是构件。二进制代码构件是编译后代码的包,二进制库是一个构件。可执行代码构件含有可执行代码。每种构件都含有某种逻辑类或接口的实现代码。构件与类或接口的实现的关系是实现关系。
构件的接口说明了它支持的功能。接口中的每个操作最终都必须映射到构件支持的实现元素上。
系统实现的静态可执行结构可由内部互连的构件集来表示。构件之间的依赖关系说 明一个构件的实现元素需要另一个构件的实现元素提供服务。这种情况下,要求提供服务者在构件之间是公共可见的。构件可以有私有元素,但是这些元素不能直接为其他构件提供服务。
构件可以包含其他构件。一个被包含构件仅是其包含者的另一实现元素。
构件实例是节点实例上的构件的一个实例。源代码和二进制代码构件的实例可以驻留某个特定节点的实例上,但最有用的还是可执行构件实举例:如果一个可执行代码构件的实例定位于一个节点的实例,则构件支持的实现类的对象在定位到节点的实例上后可执行操作。否则,位于节点实例上的对象不能执行操作,必须被移动或者复制到其他节点实例后才能执行操作。
如果一个构件没有身份标识,则它的所有实例都是相同的。其中哪个支持对象的操作都可以。它们的行为是相同的。因为没有身份标识,构件实例自身没有值或者状态。
身份特征。一个有身份标识的构件拥有身份和状态。带有定位于其上的物理对象。(所以,节点实例上包含构件实例)。它可以有属性,与构件其他对象的组成关系,与其他构件的关联。从这一角度来看,它是一个类。但是,它的所有状态必须映射到它自身的实例上,这是构件与普通类的区别。通常用一个实现类来代表整个构件。这被称为主导类,并被看作与构件是等同的,但它们实际上是不同的东西。
对象要求有身份构件提供服务时,必须选择一个特定的构件实例,通常选用与该构件有关联的构件所拥有的对象之一。因为每个有身份构件实例有状态,因此要求不同的实例将产生不同的结果。
举例
例如,一个拼写检查器是一个构件。如果它有固定的字典,则可被视为无身份标识的构件。它的所有实例产生相同的结果,而且对过去的要求没有记忆功能。如果可以对字典进行更改,则它就是有身份标识的构件。对应拼写检查器的不同实例,字典有不同的版本。要求服务时必须指明所选用的字典。通常,目标构件在特定上下文环境中隐含指定,但这是设计中必须考虑到的一个选择。
结构
一个构件支持一系列实现元素,例如实现类。也就是说,构件提供元素所需代码。一个实现元素可能被多个构件支持。
构件可以有操作和接口,这些都由其实现元素实现。
一个标识符构件是物理实体的物理容器,例如运行时的对象和数据库。为了给其内部元素提供句柄,它可以有属性或者向外的关联,这些必须由其实现元素实现。一个有身份标识构件可以指定一个支持所有公共属性和操作主导类,但是这样的类仅是该构件的一个实现元素。
表示法
构件被表示为一个矩形,其一侧有突出的两个小矩形。构件名字标在矩形中。(图13-60)。
构件实例有各自的名字,用冒号与构件名字隔开。名字有下划线,以区别于构件类型名字(见图13-61)。构件实例的符号可以画在节点符号内,表示构件实例位于
图13-60构件
节点实例上。(图13-62)。如果构件没有身份标识,实例名字将被省略。属于有身份标识的构件实例的对象可以画在其内。带有属性或含有对象的构件自动成为有身份标识的构件。
一个主导类包含构件的接口。它可以被表示为类图形,并且在类图形右上角有作为构造型图标的构件符号。在这种情况下,构件和它的主导类共享相同的接口,而且主导类可以通过组合链访问到构件中的任何一个对象。图13-63 是一个例子。
图13-61 带有对象的标识符构件实例
图13-62节点上的构件实例图13-63 构件的主导类
外部对象可以使用的操作和接口可直接在类的符号中表示。这些是类似类(class-like)的行为。子系统的内容在单独的图中表示。如果不需要表示子系统的可实例化特征,可以使用普通包的表示法。
从一个构件到另一个构件或者模型元素的依赖关系用带有箭头的虚线表示,箭头指向提供服务的元素(图13-64)。如果一个构件是某个接口的实现,可以用线将一个圆连到构件符号来简化的表示。实现一个接口意味着构件的实现元素支持接口的所有操作。如果一个构件使用了其他元素的接口,依赖关系可以用带箭头的虚线表示,箭头指向接口符号。使用一个接口说明构件的实现元素只需要服务者提供接口所列出的操作。(但用户还可以依赖于其他接口)。
讨论
下列扩展定义说明了设立构件的意图,以及确定系统的一个部分是否被作为有意义构件的考虑。
。构件是重要的,它的功能在功能和概验上都比一个类或者一行代码强。典型的,构件拥有类的一个合作的结构和行为。
。一个构件基本独立于其他构件,但是很少独立存在。一个给定构件与其他构件合作完成某种功能,为了完成这项功能,构件假设了一个结构化的上下文。
图13-64 构件的依赖关系
。构件是系统中可以替换的部分。它的可替换性使得可以用满足相同接口的其他构件进行替换。替换或者插入构件来形成一个运行系统的机制一般对构件的使用者是透明的。对象模型不需要多少转换就可使用或利;用某些工具自动实现该机制。
。构件完成明确的功能,在逻辑上和物理上有粘聚性,因此它表示一个更大系统中一段有意义的结构和/或行为块。
。构件存在于具有良好定义结构的上下文中。它是系统设计和组建的基石。这种定义是递归的,在某种层次上抽象的系统仅是更高层次抽象上的构件。
。构件不会单独存在,每一个构件都预示了它将处于的结构和/或技术的上下文。
。一个构件符合一系列接口。符合一个接口的构件满足接口指定的约定,在接口适用的所有上下文中都可替换。
标准元素
文档document),可执行(executable),文件(file),库(library),位置(location),表(table)
76.构件图(component diagram)
表示构件类型的组织以及依赖关系的图。
语义
构件图表明了软件构件之间的依赖关系,包括源代码构件,二进制代码构件和可执行代码构件(图13-64)。软件模块可以用一个构件来表示。有些构件存在于编译时,有些存在于连接时,有些存在于执行时,有些在多种场合存在。一个编译时构件只在编译时有意义。在这种情况下运行时构件是可执行的程序。
构件图只有描述符形式,没有实例形式。要表实构件实例,应使用部署图。
表示法
构件图表示了构件类元,以及其中定义的类和构件间的关系。构件类元还可以嵌套在其他构件类元之中,从而表示定义关系。
构件中定义的类在构件中表示。虽然对各种大小的系统而言,提供构件中定义的类的列表可能比表示符号更方便。
可以用包含构件类元和节点类元的图来表示编译依赖关系,该关系用带箭头的虚线表示,(依赖关系),箭头从用户构件指向它所依赖的服务构件。依赖关系的类型用语言说明的,可作为依赖关系的构造型显示。
图还可以用于表示构件之间的接口和调用关系。虚线箭头从一个构件指向其他构件上的接口。
见构件(component)可以得到构件图的实例。
77.组成聚集(composite aggregation)
见组成(composition)。
78.组成类(composite class)
通过组成关系与一个或者多个类相关联的类。
见组成(composition)。
79.组成对象(composite object)
组成对象代表一个由紧密结合的部分构成的高水平对象,它是组成类的一个实例,隐含了类与其成分之间的组成聚集0。组成对象与合作类似。(但是更简单,而且更严格)。然而,它由静态模型中的组成定义,而不是由合作中的上下文依赖关系定义。
见组成(composition)。
语义
组成对象与它所有的组成部分之间有组成关系。这意味着它负责这些部分的创建和销毁,同时没有其他对象有类似的责任。换句话说,没有这些组成部分的垃圾收集点;组成对象可以,也必须在它死亡时销毁这些组成部分,或者把责任转交格其他对象。
组成关系通常用与组成对象相同的数据结构内的物理限制实现(通常为一个记录)。物理限制保证了组成部分的生命周期与组成对象的生命期匹配。
表示法
对象和链的网络可嵌套在对象符号中的图形分格中。图形分格是在属性分格(可以省略)下的附加分格。图形区域内包含的对象和链是组成对象的组成部分。但是,路径超出组成对象范围的链不是对象的组成部分,而是分立对象之间的链。
举例
图13-65是一个组成对象,名为桌面窗口,它由不同部分组成。它包括ScrollBar类的多个实例,每个实例在组成对象中有自己的名字和角色。例如,horizontalBar和verticalBar都是滚动条,但是它们的行为不同。在这一点上,它们类似于合作角色。
图13-65 组成对象
80.复合状态(composite state)
包含并行(正交)或顺序(互斥的)子状态的状态。
见复杂转换(complex transition) ,简单状态(simple state),状态(state)。
语义
组成状态可以使用"与"关系分解为并行子状态,或者通过"或"关系分解为互相排斥的互斥子状态。状态精化只能使用两种方法之一。其子状态还可以用两种方法之一进一步进行分解。如果一个顺序组成状态是活动的,则只有一个子状态是活动的。如果一个并发组成状态是活动的,则与它正交的所有子状态都是活动的。分解结果为一与-或树。每个状态机有一个顶层状态,它是组成状态。
系统在同一时刻可以包含多个状态。活动状态集称为活动状态结构。如果一个嵌 套状态是活动的,则所有包含它的组成状态都是活动的。如果对象允许并发,则可以有多个并发子状态同时为活动的。
见复杂转换(complex transition)以了解并发执行;图13-51显示了一棵与-或树。
新创建的对象始于初始状态,这是最外层的组成状态中必须包含的状态。创建对象的事件可以用来触发某个离开初始状态的转换。关于创建事件的讨论也适用于初始转换。
转入外层终态的对象将被销毁而停止存在。
结构
一个组成状态包括一系列子状态。组成状态可以是并发或者顺序的。
一个顺序组成状态最多可以有一个初始状态和一个终态,同时也最多可以由一个
浅(shallow)历史状态和一个深(deep)历史状态。
一个并发组成状态可能没有初始状态,终态,或者历史状态。嵌套在它们里的任何顺序组成状态可包含这些伪状态。
表示法
组成状态是包含有从属细节的状态。它带有名字分格,内部转换分格和图形分格。图形分格中有用于表示细节的嵌套图。所有的分格都是可选的。为了方便起见,文本分格(名成分格和内部转换分格)可以缩略为图形分格内的制表符,而无需水平延伸它。
将图形分格用虚线分成子区域,表示将并发组成状态分为并发子状态。每个子区域代表一个并列子状态,它的名字是可选的,但必须包括带有互斥的子状态的嵌套状态图。用实线将整个状态的文字分格与并发子状态分格分开。
在图形分格中,用嵌套的状态表图表示将状态扩展为互斥的子状态。
初始状态用小实心圆表示。在顶层状态机中,源自初始状态的转换上可能标有创建对象的事件。否则转换必须是不代标签的。如果没有标签,则它代表所有到封装状态的转换。初始转换可以有一个动作。初始状态是一个符号设备,对象可以不处于这种状态中,但必须转换到实际的状态中。
终态用外面套了圆环的实心圆表示(牛眼)。它表示封装状态中的活动完成。它触发标有隐含的完成事件活动的封装状态上转换(通常为无标签转换)。
图13-66 顺序组成状态举例
图13-66 表示包含两个互斥子状态的顺序组成状态,一个初始状态和一个终态。当组成状态为活动时,子状态Start(初始状态的目标状态)首先变为活动的。
图13-67表示带有三个正交状态的并发组成状态。每个并发子状态又进一步分为顺序子状态。当组成状态Incomplete成为活动状态时,初始状态的目标状态成为活动的。当三个子状态都达到终态后,外部组成状态的完成转换被触发,Passed成为活动状态。如果在Incomplete为活动状态时发生fail事件,则所有的三个并发子状态结束,Failed成为活动状态。
图13-67 并列组成状态
81.组成(composition)
是指一种带有很强主从关系,成分的生命期一致的聚集关联形式。一个部分可以仅属于一个组成。没有固定多重性的部分可以在组成创建后再被创建。但是一旦被创建,这些部分将与组成同时存在并同时消亡(共享生存周期)。这些部分也可以在组成消失前被移开。组成可以是递归的。
见聚集(aggregation)、关联(association)、组成对象(composite object)。
语义
带有很强的聚集关联形式被称为组成。组成是带有额外约束的聚集关联,一个对象在某一个时刻可以只属于一个组成,而且组成对象对其所有成分的安置负完全责任。作为第一个约束的结果,所有组成关系的序列(带有组成属性的所有关联)形成了一个对象和组成链的树林。一个组成部分不能同时被两个组成对象共享。这符合物理的组成概念--一个部分不能同时成为两个对象的直接成分(虽然在不同粒度层次的树中它可以间接的成为多个对象的成份)。
组成对其组成部分负责,是指它要负责其成分的创建和销毁。在实现过程中,它负责成分的内存分配。在实例化过程中,组成必须保证其成分都生成了实例并与之正确的连结。它可以自行生成成分,或者对已存在的部分承担责任。但是在组成的生命期内,没有其他对象能对它的成分负责。这意味着设计组成类行为时应该了解,没有其他类可以销毁组成的成分或者对它们重新定位。在生命期内,组成如果对其成分负责,就可以增加附加部分(如果多重性允许)。如果符合度允许且别的对象承担安排它们的责任,它可以移动成分。一旦组成被销毁,它必须销毁其成分,或将它们的安置权交给其他对象。
这个定义概括了组成的普遍逻辑和实现特征。例如一个带有值表的记录是一个对象及其属性的常见实现。当为记录分配空间时,其属性的存储空间也自动分配了,但属性值需要初始化。记录存在时,它的属性不能移动。记录除配时,属性的存储空间也将被除配。其他对象不能影响记录中属性的空间分配。记录的物理特性符合组成的约束。
组成的定义便于无用单元回收,如果组成自身被销毁,则指向其成分的唯一指针也被销毁,成分将不能访问,易于无用单元回收。收回不可访问单元对于无用单元回收来说是很简单的,而这正是区分组成与其他聚集的一个原因。
注意:成分不一定要被实现成为组成的存储块中的物理成分。如果一个成分独立于组成,组成有责任根据需要为它分配/除配存储空间。例如c++中组成的构造和析构功能的实现。
一个对象在同一时刻只能属于一个组成对象。这并不排除一个类在不同的时刻或者在不同的实例中成为多个类的成分。但同一时刻,一个对象只能存在一个组成链中。 换言之,一个成分可能属于"或"关系的组成中。一个对象在其生命周期里可以是不同组成对象的成分,但是每个时刻只属于一个组成对象。
结构
关联端的聚集特性可以为下列值:
none 所附类元不是聚集或组成。
aggregate 所附类元是聚集,另一端是其成分。
composite 所附类元是组成,另一端是其成分。
关联至少应该有一端的值为none。
表示法
在关联路径上,与组成元素相连的一端带有实心的菱形表示组成关系。(图13-68)。多重性用常规方法表示,必须为1或0..1。
图13-68 组成关系表示法
另外,组成关可以用组成符号嵌套成分符号表示(图13-69)。嵌套的类元可以在其组成元素中有多重性。多重性用字符串在成分的符号的右上角标明。如果省略多重性标示,默认值为"多"。组成关系中的嵌套元素可以有角色名。角色名在其类型前标出,语法为:
rolename:classname
其角色名是隐含的从组成到其成分的组成关联的角色名。
画在组成关系边界内的关联被认为是组成的成分。由这样的关联的一条链连结的任何对象必须属于同一个组成。超出组成关系边界的关联不是组成的成分,由这样的关联的一条链连结的对象可以属于同一个组成,也可以属于不同组成。(图13-70)
图13-69 图形嵌套的组成关系
图13-70 组成之内和之外的关联
注意,属性实际上是类和类的属性之间的组成关系。(图13-71)。但是通常属性被保留为基本类型数值(数字、字符串、数据),而不是类的引用。因为在属性表示中看不到部类元的其他关系。
注意,组成的表示法与合作的表示类似。当合作的所有参与者是唯一组成对象的成分时,组成可以被看作一种合作。
图13-72是多重组成。
图13-71 属性是组成的一种形式
图13-72 多重组成
讨论
(见聚集的讨论,了解聚集、组成、以及简单关联何时适用)
组成与聚集是元关系--它们超越了单个的关联,对整个系统施加约束。组成在组成关系中有定义。一个对象最多能有一个组成链(到组成),但是可能来自多个组成关联。即使关连链来至不同的关联,整个由组成和聚集链以及对象构成的图必须成环。注意,这些约束适用于实例域--聚集关联自身常常成环,递归结构也总要求有关联环。
请考虑图13-73中的模型。每个Authentication是一个Transaction的组成部分,Transaction可以是Purchase或Sale。但是并不是每一个Transaction都需要有一个
图13-73到抽象组成类的组成
图13-74 共享部分的类
Authentication。从图中可得出Authentication没有其他的组成关联。每个Authentication对象必须是一个Transaction对象(多重性为1)的组成部分;一个对象最多只能属于一个组成(根据定义);Authentication已经是一个对象的组成部分(如图所示),所以Authentication不能再成为其他组成关联的成分。可以由Authentication管理自身的存储区。虽然不是所有Transaction都有需要管理的Authentication,但是 总可得到一个Transaction来承担管理责任。(当然,如果设计者需要,Authentication可管理自己)
现在请考虑图13-74,Autograph可以可选的成为Transaction或者Letter的部分。但是不能同时属于二者(由组成的规则决定)。该模型允许Autograph开始时是Letter的部分,随后再是Transaction的部分(此时,Autograph必须不是Letter的部分了)。实际上,Autograph不一定要是任何对象的部分。而且从本图中我们不能排除Autograph成为图中未标出的类或后来增加的类的部分的可能性。
如果强调Autograph必须是Letter或者Transcation的部分呢?这需要重新设计模型。如图13-73,可以在其中增加一个Letter和Transaction上的新抽象超类(称为Document)。和Autograph的组成关联从原来的类移到Document上。同时,Autograph到Document的多重性为1。
图13-75 组成关联的泛化
这种方法存在一个小问题:Document到Autograph的多重性必须被设为可选的,从而削弱了Transaction对Autograph的强制包含关系。可以用组成关联的泛化关系为这种情况建立模型,如图13-75 所示。Autograph与Transaction间的组成关联被设定为Autograph与Document之间的组成关联的孩子。多重性为孩子声明(注意,它们仍然与祖先一致,因此用孩子替代父母)。此外,通过在两个组成上增加约束条件,要求必须在两者中选一种,就可以使用原来的模型,。
82.具体(concrete)
是指一个可以直接实例化的可泛化元素(如类)。它的实现必须经过充分的说明。对类而言,它的所有操作必须被实现(由类或者其祖先)。反义词:抽象
见 直接类(direct class)、实例化(instantiation)
语义
只有具体类元可以被实例化,因此泛化体系的叶节点必须是具体的。换言之,所有抽象的操作和其他抽象属性都必须最终在某一个后代上实现。(当然程序没有完成时,抽象类可能没有具体后代。例如有待用户扩充的框架等。但是在提供具体后代之前,这些类都不能在实现中使用)。
表示法
具体元素的名字用常规字体表示,抽象元素的名字用斜体。
83.并发(concurrency)
在同一时间间隔内,两个或两个以上的活动的执行。并不隐含的要求这些活动同步。通常,除了明确的同步点之外,它们的活动是相互独立的。可以通过插入或者同时执行多个线程来实现并发。
见复杂转换(complex transition)、组成状态(disjoin)、线程(thread)。
84.并发子状态(concurrency substate)
一个可以与同一个组成状态中的其他子状态同时存在的子状态。
见 组成状态(composite transition), 互斥子状态(disjoin substate)
85.条件线程(conditional thread)
活动图中,由分叉的监控输入段开始,由相应的结合点的输入段结束的一块区域。
见 复合状态(composite state)、复杂转换(complex transition)
86.冲突(conflict)
是指从几个类继承相同名字的属性或操作的情况,或一个事件触发多个转换,或者其他由正常规则可能产生矛盾结果的情况。根据不同模型元素的不同语义,用冲突化解规则来解决冲突,冲突可能是合法的但产生了一个不确定结果,或者它可能表明了模型形式错误。
讨论
冲突化解规则可以避免冲突出现。例如:如果多个类定义了相同的特征,使用最先的超类定义的该特征(这要求超类有序)。UML通常没有定义冲突化解规则,因为完全依赖它们是危险的。冲突易被忽视,常常成为模型中更深层问题的诱因。与其依赖这些微妙且易引起混乱的规则,不如要求一个精确的系统。在某种工具或者程序设计语言中,存在着这样的规则。最好在使用这些规则时,有工具给出警告,使建模者意识到冲突的出现。
87.约束(constraint)
它是一个语义条件或者限制的表达式。UML预定义了某些约束,其他可以由建模者自行定义。约束是UML的3个可扩展机制之一。
见表达式(expression)、构造型(stereotype)、标签值(tagged value)。
见第14章的标准元素,那里有预定义的约束列表。
语义
约束是一些用文本语言中的陈述句表达的语义条件或者限制。
通常约束可以附加在任何一个或者一列模型元素上。它代表了附加在模型元素上的语义信息。每个约束有约束体和翻译语言。约束体是约束语言中关于条件的布尔表达式的字符串。约束应用于有序的一个或一列模型元素。应注意,这里的语言可以是形式化语言,也可以是自然语言。如果是自然语言,则约束是非形式化的,不能自动执行(但是形式化的约束也不一定都可以自动执行)。UML提供了约束语言OCL[Warmer-99],也可以使用其他语言。
某些常用约束有名字,从而避免每次使用时写出完整的语句。例如:两个共享同一个类的关联之间的异或(xor)约束表示共享类的一个对象在同一时刻只能属于关联的一方。
见第14章的标准元素,可以看到UML中预先定义的约束列表。
约束不是可以执行的机制,而是一种断言。它是表示必须由系统的正确设计来实施的限制。如何保证约束的实现是设计的任务。运行时,约束作用于系统实例的"稳定"时刻--即,在操作的执行和没有原子转换正在进行的时刻的中间时刻。在一个操作的执行过程中,可能在某些时刻暂时违反约束。
约束不能作用于自身。
即使后代上定义了额外的约束,继承的约束--在祖先模型元素或者构造型上定义的约束--必须被遵守。继承约束不能忽略。如果有这样的需要,说明模型的结构不好,应该重新构造。但是,可以增加限制条件来加强继承约束。如果元素的继承约束有冲突,说明模型为非良性结构。
表示法
约束用大括号({})中的文本串表示。文本串是用约束语言写的代码体。
工具应该提供一种或几种形式化的约束语言。一种描述约束的预定义语言是OCL。根据模型的不同,一些计算机语言(如C++)也可以用来表示约束。此外,约束还可以用自然语言描述,这时,约束的翻译和执行由人完成。每一种约束的语言是约束的一部分,但是在图中不一定标出。(工具将保留其记录)。
对于分格中用字符串表示的一列元素(例如类的属性):约束可能作为元素列的入口(见图13-76)。入口不代表一个模型元素,而是作用于其后列出的模型元素上的运行约束。作用范围直到出现另一个运行约束,或者元素列到头。运行约束可以被列表中稍后出现的新约束所替代。要消除运行约束,可以用空的约束来替代它。附属于某个列表元素的约束不能替代运行约束,但是可以为其增加额外的限制。
对于简单图形符号(例如类或者关联路径):约束字符串可以标在图形符号边上,如果图形符号有名字,就标在名字边上。
图13-76 带列表的约束
图13-77 约束表示法
对于两个图形符号(例如两个类或两个关联):约束用虚线箭头表示。箭头从一个元素连向另一个,并带有约束字符串(在大括号内)。箭头的方向与约束的信息相关。
对于三个或更多的图形符号:约束用注释符号表示,并用虚线与各个图形符号相连(图13-77)。这种表示法适用于其他情况。对三个或更多的同类路径(例如泛化路径或者关联路径),约束标在穿过所有路径的虚线上。为避免混淆,不同的连线可以标号或加标签,从而建立它们与约束之间的对应关系。
讨论
约束是关于模型本身的语义表述,而注释是没有语义效用并可以附加在的模型元素和表示元素的文字语句。约束和注释都可以用注释符号表示。原则上,约束是可由工具执行的。在实践中,某些约束难以形式化的表述,要由人工强制执行。从广义上讲,模型中的许多元素都是约束,但是这里的约束是指那些不能用内置模型元素表达的,必须单独用语言声明的约束语句。
约束可以使用多种语言,甚至使用人类语言来表述,但是工具不能验证人类的语言描述的约束。OCL语言[Warmer-99]是用于UML约束的表达,但是某些情况下,某些程序设计语言可能更适用。
因为约束用文本字符串表示,普通的建模工具可以不必理解其含义就能读入并维护它。当然,用来验证或执行约束的工具或者插件必须能理解目标语言的语法和语义。
一些约束可以附加在构造型定义上,这说明所有属于此构造型的元素都处于这些约束下。
执行 当模型中有约束时,不一定要求给出约束被违反后的操作。模型只是对可能出现的情况的声明,使这些情况发生是实现的任务。一个程序可以包含了断言和其他验证机制,违反约束应被视为程序失败。当然,如果模型能够帮助产生结构正确或可被验证的程序,则此模型达到了目标。
标准元素
不变量(invariant),后置条件(postcondition),前置条件(precondition)。
88.构造(construction)
软件开发过程中的第三阶段,进行详细设计,系统实现,软件,固件和硬件测试。在这一阶段,分析视图和设计视图基本完成,并完成大部分实现图和一些部署图。
见开发过程(development process)。
89.构造函数(constructor)
创建并初始化类的实例的一种类作用域操作,可以作为操作的构造型使用。
见 创建(create)、实例化(instantiation)
90.包容器(container)
包含其他对象的对象,它提供了访问或迭代其内容的操作,或者一个描述此类对象的类。例如数组,列表,集合。
见聚集(aggregation)、组成(composition)
讨论
通常不必明确地对包容器建模。它们通常是关联的"多数"端的实现。在多数模型中,多重性大于1足以标明正确的语义。当使用设计模型生成代码时,用于实现关联的包容器类可以被指定为使用标签值的代码生成器。
91.语境(context)
与某个目标相关的模型元素集的视图,如执行一个操作或者构造一个模型。语境是模型的一部分,它为其中的元素提出约束或者提供环境。合作为其内容提供语境。
见合作(collaboraion)。
92.控制流(control flow)
在交互中,控制的后继轨迹之间的关系。例如活动图或合作。
见动作(action)、活动图(activity graph)、合作(collaboration)、完成转换(completion transition)、消息(message)、对象流状态(object flow state)、转换(transition)
语义
交互视图代表了计算过程中的控制流。交互中的原始元素是活动和对象。控制流代表活动与其参与者和后继的活动之间的关系,以及动作和它的输入和输出对象间的关系。在简化的格式中,控制流是一个对象到另一个对象,或者一个对象在不同时刻的不同版本之间的派生计算。(包含对象输入输出的控制流称为对象流)。
表示法
在合作图中,控制流用附加在连接类元角色(代表对象及其实例)的关联角色(代表连结)上的消息表示。在活动图中,控制流用活动符号之间的实心箭头表示。对象流用活动符号或者控制流箭头和对象流状态符号之间的虚线箭头表示。见相关章节,以作进一步了解。
93.控制图标(control icons)
简略的表示各种控制模式的可选符号。
见活动图(activity graph)、合作(collaboration)、状态机(state machine)
表示法
下列符号为活动图而设计,但也可用于状态图。这些符号不允许那些不能用基本符号表示的内容,但对于常规控制模式而言,它们是方便实用的。
分支 分支是由单一状态发出的一系列转换,必须总有一个转换上监护条件被满足。换言之,如果发生触发事件,只有一个转换能够激发。这些监护条件代表了控制的分支。如果是完成转换,则一个分支是抽象决定(pure decision)。为了方便起见,可以有一个分支的输出被标为"else"。如果没有选择其他路径,就走这一条。
分支由有一个输入箭头和多个输出箭头的菱形表示。输入箭头上标明触发事件(如果有),每个输出上标有监护条件(图13-78)。
合并 合并是两个或两个以上的可选控制路径聚集的地方。它与分支相反。菱形同时是分支和结合的标志。如果有多个输入,说明符号代表合并。如果有多个输出箭头,说明符号代表分支(图13-78)。不一定必须有合并(多重转换进入单一状态称为合并),但它们对于表示与先前分支的匹配还是很有用的。
信号接收 信号接收用凹五边形表示。信号的内容在符号内标出。由一个不带标签的转换箭头从前驱状态指向五边形,另一个不带标签的转换从五边形指向其后继状态。该符号取代了转换上的事件标签,该转换在前驱活动结束后,事件发生时被触发(图13-79)。此外,可以用虚线箭头从对象符号指向五边形的缺口,表示信号的发送者。
信号发送 信号发送用凸五边形表示。信号的内容在符号中标出。有一个不带标签的转换从前驱状态指向五边形,另一个不带标签的转换由五边形指向其后继状态。这个符号取代了转换上的"发送信号"标签(图13-80)。此外,可以用虚线箭头从五边形的顶点指向对象符号,表示信号的接收者。
图13-78 分支与结合
图13-79 信号接收
图13-80 信号发送
举例
如图13-81,EnterCreditCardData和ChargeCard是活动。当它们完成后,执行转入下一步。在EnterCreditCardData完成后,出现了根据金额区分的分支:如果所需金额大于25美元,则要求出示证明。一个request信号被送往信用中心。在普通状态机中,它可以表示为从EnterCreditCardData转出的转换上的一个活动;二者意义相同。AwaitAuthorrization是一个等待状态。它不是内部完成的活动,而必须等待来自信用中心的外部信号(authorize)。当信号出现,触发了一个常规转换,系统进入ChargeCard活动。触发事件可以可以作为AwaitAuthorrization和ChargeCard之间的转换上的标签,二者是同一事物的不同表示法。
图13-81 表示发送和接收信号的活动图
图13-82是相同的例子,只是没有使用特殊的控制符号。