UML 说明:类,构造型为 <<capsule>>。注意该表示基于 UML 1.5 表示法。该表示法的大部分内容可以在 UML 2.0 中使用概念:结构化类表示。
关于更多信息,请参阅 UML 1.x 和 UML 2.0 之间的区别。
封装体是一个组合元素,如下图所示。
封装体组装
封装体可以有端口,并可能“包含”被动类和/或子封装体。它可能还有状态机,状态机完整地描述了封装体的行为。指南:封装体中描述了封装体的特定分类法以及各种使用方法。
封装体封装了控制线程。
封装体是系统中独立控制线程的抽象;它是系统中的主要并发单元。可以通过将封装体映射到特定操作系统进程和线程,使用操作系统进程和线程完成附加的控制线程隔离。到封装体的消息通过端口到达,并依序处理;如果封装体实例忙碌,则将消息排队。封装体强制“运行至完成”语义,所以当接收到事件时,将完全处理它而不论到达的其他事件的数量或优先级。
封装体通过端口与其周围的环境交互。端口是基于信号的边界对象;它作为封装体与外部世界交互的媒介。端口实施特定接口并可能依赖于某特定接口。封装体不能有除端口以外的操作或公共部件,端口是它与外部世界交互的唯一方法。
每个端口在协作中扮演一个特定角色。该协作描述该封装体如何与其他对象交互。为捕获这些交互的复杂语义,将端口与协议相关联,而协议定义了连接的封装体端口之间的有效信息流(信号)。协议捕获封装体之间存在的契约职责。通过强制封装体仅通过端口进行通信,可能将封装体的内部实施与封装体周围的环境完全分离。
这使封装体有很高的可重用性。
封装体的状态机直接实现简单封装体的功能。更复杂的封装体将状态机与由连接器连接的协作子封装体组成的内部网络结合起来。这些子封装体本身就是封装体,并且可以将自身分解成子封装体。可以将此类型的分解进行至任意必要的深度,使得可以仅使用这一组基本的结构建模构造,对任意复杂的结构建模。状态机(对组合封装体是可选的)、子封装体以及它们的连接网络代表封装体的实施部分,并且对外部观察者是隐藏的。
封装体可以是一个组合元素。
封装体可以由其他封装体和被动类组成。封装体和被动类通过协作中的连接器或链接连接在一起;该协作定义封装体的“结构”,并因此称为“规范协作”。封装体可以有一个状态机,该状态机可以通过封装体的端点端口发送和接收信号,并控制内部结构的某些元素。因此,可以认为该状态机实施反射行为,即控制封装体操作自身的行为。
端口是一种对象,其用途是作为封装体实例的边界对象。它们由封装体实例“拥有”,其含义是它们随封装体一起创建,并在封装体销毁时销毁。每个端口都有其标识和状态,这些标识和状态与拥有它们的封装体实例的标识和状态不同(正如任何部件都与其容器不同)。
虽然端口是充当接口的边界对象,但是它们并不直接映射到 UML 接口。UML
接口是一种纯粹的行为事物,它没有实施结构。另一方面,端口包括结构和行为。它是封装体结构的组合部件,而不仅仅只是对其行为的约束。它实现了可以称为“清单接口”的体系结构模式。
在 UML 中,将一个端口建模为具有 <<端口>>
构造型的类。如早先提到的,由端口所扮演的协议角色定义该端口的类型。因为协议角色是抽象类,与该实例对应的实际类是实施与该端口关联的协议角色的类。在 UML
中,将端口和协议角色之间的关系称为实现关系。该关系的表示法是一条虚线,在规范末端有一个实心三角箭头。它是泛化关系的一种形式,通过该关系,源元素(端口)仅继承目标(协议角色)的行为规范,而不是其结构。
封装体与其端口之间存在组装关系。如果该关系目标端的多重性大于一,则表示在运行时存在该端口的多个实例,每个实例参与该协议的一个单独实例。如果多重性是一个范围内的值,则表示端口数可以在运行时改变,并且可以动态地创建和清除端口(可能受到约束)。
端口、协议和协议角色
上图显示了名为 b 的单个端口的示例,该端口属于封装体类 CapsuleClassA。该端口实现了协议类 ProtocolA 定义的主要协议角色。注意实际端口类
PortClassX(是一个会随实施不同而不同的实施类)在实施阶段之前通常不是建模者感兴趣的内容。感兴趣的内容应该是该端口实施的协议角色。由于此原因以及为了表示方便,通常不会使用图 1
中所示的表示法,而是使用以下部分中描述的更精简的形式替换它。
表示法
在类图中,在所示的作了特殊标记的列表部分中列出封装体的端口。端口列表部分通常显示在属性和操作员列表部分之后。该表示法利用了 UML 的特性,该特性允许附加特定的命名部分。
端口表示法 - 类图表示
所有外部端口(中继端口和公共端端口)都有公共可视性,而内部端口都有受保护的可视性(例如,端口 b2)。端口的协议角色(类型)通常由一个路径名标识,因为协议角色名称仅在给定协议范围内是唯一的。例如,端口 b 扮演主角色,该角色在名为
ProtocolA 的协议类中定义。对于非常常见的二进制协议情况,将使用一个更简单的表示法约定:将使用一个后缀波浪号(“~”)来标识成对的协议角色(例如,端口 b2),而基本角色名称是隐式的,没有特殊表示法(例如,端口
b1)。多重性大于一的端口有一个用方括号括起来的多重性因子。例如,端口 b1[3] 有一个多重性因子 3,而 b5[0..2] 指定的端口有可变的实例数,最大不超过 2。
连接器表示一个通信信道,该信道为支持特定的基于信号的协议提供传输设施。连接器的一个关键特性是它们只可以互连那些在与该连接器相关联的协议中扮演补充角色的端口。原理上,各协议角色不一定要属于同一协议,但如果是这样,则它们必须与该连接器的协议兼容。
连接器是互连两个或更多端口的、基于信号的通信信道的抽象视图。连接所绑定的端口必须扮演协议中互为补充但兼容的角色。在协作图中,使用互连适当端口的关联角色表示它们。如果从该图中抽象出端口,连接器实际上捕获了封装体之间的关键通信关系。这些关系在体系结构方面很重要,因为它们标识了通过直接通信可以互相影响的封装体。包含端口以使封装体的封装符合信息隐藏和问题隔离的原理。
连接器和协议之间的相似性也许暗示这两个概念是等价的。但是,情况不是这样,因为协议是期望行为的抽象规范,而连接器是物理对象,其功能仅仅是将信号从一个端口传送到另一个端口。通常,连接器自身是被动管道。(实际上,物理连接器有时会偏离指定行为。例如,由于一个内部故障,连接器可能丢失、重新排序或复制消息。此类故障在分发式通信信道中很常见。)
使用对应封装体类的两个或更多端口之间存在的关联对连接器建模。
(对于连接器有物理属性的高级应用程序,可以使用一个关联类,因为连接器实际上是一个有状态和标识的对象。对于端口,用于实现连接器的实际类是一个实施问题。)通过连接的端口隐含了与支持的协议的关系。因此,表示连接器不需要 UML
扩展。
使用规范协作表示封装体的完整内部结构。此协作包含其所有端口、子封装体和连接器的规范。与端口类似,子封装体和连接器完全归封装体所拥有,不能脱离封装体单独存在。当创建封装体时创建它们,当清除封装体时清除它们。
结构中的某些子封装体可能不是与包含它们的封装体同时创建的。而是在以后需要的时候,由封装体的状态机创建它们。该状态机还可以随时清除此类封装体。这遵循针对组装的 UML 规则。
封装体的结构可以包含所谓插件角色。它们实际上是动态填充的子封装体的占位符。这是必需的,因为并不总是预先知道在运行时将由哪些特定对象扮演这些角色。一旦提供了此信息,则可以将相应的封装体实例(由某个其他组合封装体拥有)“插入”此类槽,并将自动建立连接器,该连接器将其端口连接到协作中的其他子封装体中。当不再需要该动态关系时,会从插件槽中“除去”该封装体,与它的相连的连接器也将卸下。
在确保显式地指定封装体之间的所有有效通信和包含关系的情况下,动态创建的子封装体和插件允许对动态更改的结构建模。这是确保复杂实时系统中体系结构完整性的关键。
还可以在规范协作图中描述端口。在这些图中,由相应的分类器角色来表示对象(即由封装体角色表示子封装体,由端口角色表示端口)。为减少视觉混乱,通常以图标形式(由小黑白框表示)显示端口角色。公共端口由端口角色图标表示,该图标横跨对应封装体角色的边界,如上图中所示。该简洁表示法允许从封装体的内部和外部连接它们,避免了不必要的交叉线,并且将它们清楚地标识为边界对象。
端口表示法 - 规范协作图
注意标签是端口角色的附加内容(adornment),不要将它们与连接器的关联关系端名称混淆。另外,因为端口名称唯一地标识了端口,为图示方便,可以围绕子封装体框周围以任何顺序排列公共端口角色。可以使用此方法将连接器线之间的交叉减到最少。
对于二进制协议情况,可以使用一个附加的构造型图标:使用一个白色填充(与黑色填充相对)方框表示扮演配对角色的端口。在该情况中,协议名称和代字符后缀已足以将协议角色标识为配对角色;协议角色名称是多余的,应当省略。类似地,在黑色方框上仅使用协议名称表示协议的基本角色。例如,如果将协议
ProtQ 中的“主”角色声明为基本角色,则下图与上图等价。该约定使连接补充协议角色时更容易看到它。
二进制协议的表示法约定
还可以使用下图中所示的标准 UML 多对象表示法以图形化方式表示具有大于一的多重性因子的端口。这不是强制的(多重性字符串已经足够了),但它强调了端口有多个实例的可能性。
具有大于一的多重性因子的端口
与封装体相关联的可选状态机是另一个封装体实施部件。但是,状态机有某些特殊属性,将它与封装体的其他要素区分开:
-
不能将它进一步分解成子封装体。它直接指定了行为。但是可以使用标准 UML 能力,将状态机分解成更简单的状态机的层次结构。
-
每个封装体最多可以有一个这样的状态机(虽然子封装体可以有它们自己的状态机)。 没有状态机的封装体是简单的子封装体容器。
-
它处理封装体的任何端点端口上的到达信号,并可以通过这些端口发送信号。
-
它是唯一可以访问其封装体的内部受保护部件的实体。这表示它作为所有其他子封装体的控制器。这样,它可以创建和清除那些标识为动态的子封装体,并且可以相应地插入和删除外部子封装体。
使用可变多重性因子简单地表示动态创建的子封装体。和插件槽类似,也可以使用纯接口类型来指定这些子封装体。这表示在实例化时,可以实例化所有支持该接口的实施类。这提供了结构规范中的通用性。
无论其附加限制如何,使用 UML 分类器和状态机之间的标准链接对与封装体关联的状态机建模。使用标准 UML 协作元素对封装体的实施/分解建模,该元素可与分类器相关联。
|