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是相同的例子,只是没有使用特殊的控制符号。
本文地址:http://com.8s8s.com/it/it2076.htm