8.2 包和可见性
8.2.1 包成员可见性
在上面显示的包及其成员的所有表示中,我们可以在成员名称之前添加一个可见性指示符。 允许的可见性修饰基于类成员上允许的可见性修饰,可见性标志紧跟在成员名称之前,通常在任何刻板印象之后。 我们在图 8.7 中演示了这一点,展示了它如何与三种可选的成员描述方法(物理放置在内部、成员列表或“&”方法)一起工作。
包中的 UML 可见性符号
+ Public
具有公共可见性的成员可见对可以访问拥有它的包(或命名空间)的内容的所有元素可见
- Private
具有私有可见性的成员仅在拥有它的包(或命名空间)内可见
~ Package
具有包可见性的成员在最近的封闭包中可见(假设任何中间拥有元素都具有适当的可见性)。 在最近的封闭包之外,标记为具有包可见性的 NamedElement不可见
不允许在包或包直接拥有的元素上使用
只对同一个包声明的其他类可见
# Protected
具有受保护可见性的成员对与拥有它的命名空间具有泛化关系的元素可见
不允许在 Packages 直接拥有的 Packages 或 Elements 上使用。 包不支持泛化/专业化
对子类可见
包中 UML 可见性符号的相互作用有时很难遵循。 很容易构建复杂的可见性情况。
构建复杂的可见性解决方案很容易。 在实际建模中,大多数情况永远不会变得复杂,因为 UML 工具通常充分理解可见性规则以强制执行正确引用。 此外,UML 工具通常支持一种拖放形式来创建引用。 由于其他引用通常在 Opaque Expressions 中找到,它们不会自动解决,因此它们不会导致工具出现任何问题。
包只能被赋予私有 (-) 或公共 (+) 可见性。 直接在包中的元素(没有介入命名空间)也可能只有私有或公共可见性。
8.2.2 内外名称
如图所示,P1、C1 和 C2 的直接元素可以通过它们的简单名称 C1 和 C2 相互引用。 在 P1 中,如果 C1 需要引用 C2 中的属性 a1,它将使用 C2. a1。同样,如果 C2 需要引用 C1 中的操作 b(),它将使用 C1.b()。
同样,在Package P2中,如果C1和C3可以使用其他成员的简单名称,则C1和C3。 如果他们想参考彼此的属性,他们可以使用 C3. a1 或 C1.b()。
那么问题来了,P2 中的元素如何直接引用 P1 中的元素,或者 P1 中的元素如何直接引用 P2 中的元素。这里的问题是外部名称(在 P1 中)和内部名称(在 P2 中)有一些重叠。 让我们假设一切都标记为可见 (+)。
要从 P1 引用内部元素,我们需要使用限定名称。限定名称包括从源到目标的包链。 为了引用内部元素 P1,我们使用 P2::C1 和 P2::C3。如果我们需要从 P1 引用它们的特征,它看起来像P2::C3.a1 或P2::C1.b() .
Package to Package 和 Package to Element 使用“::”作为分隔符。
属性到元素或操作到元素使用“::”作为分隔符。
要引用P2的外部元素,我们可以将C2称为C2,我们可以将C2的属性称为C2.a1。
但是,我们不能直接引用 C1,因为名称 C1 被 P2 级别的 C1 的存在所阻塞。
使用 C1 作为参考将引用本地 C1。我们必须使用限定名称来获取 P1 的 C1,即 P1::C1。 P2 可以将 C1 的属性称为 P1::C1.b()。
然后,图中的每个元素都可以引用 C2 和 C3,因为这些名称元素被定义一次,并且它们通过公共元素的规则可见。 因此,无论是由 P1 还是 P2 中的某些内容引用,C2 上的操作仍将是 c2.b()。 类似地,无论是由 P2 还是 P1 中的某些内容引用,C3 上的操作仍然是 C3.b()。
当存在对“外部”元素的引用时,如果本地包中存在具有该名称的元素,则该引用将被阻止。 如果我们希望从不同级别获取阻塞元素的版本,则引用必须使用限定名称,因为本地名称将“隐藏”外部名称。 这种名称阻塞可能是由引用和目标之间任何级别的重复名称引起的。
8.2.3 命名空间和可分辨名称
正如第 4 章 UML 的组织及以后提到的,包就像文件抽屉中的文件夹或计算机系统上的目录。一个特定的文件或一张纸一次只能在一个文件夹/目录中,尽管您可以在多个文件夹中分发副本。 UML 包和计算机目录命名空间。这些需要为其内容提供唯一且可识别的名称。
计算机的操作系统不允许您在同一目录/文件夹中有两个具有相同名称的文件。一个包中不允许有两个同名的元素(相同类型)。与在任何 VIEW 中一样,如果一个元素在一个包中出现两次,则每次出现都只是同一事物的表示。
同样,如果同名同类型出现在不同的Package中,则它们是不同的Element。
UML 支持其他命名空间,可以包含元素。大多数人没有意识到,但 Class 的隔间也是 Namespaces。特定的类不能具有不可区分的属性或不可区分的操作,就像包不能具有不可区分的元素一样。
不可区分名称的规则是什么?
属性:
命名空间中的两个属性,通常命名空间是一个类,不能具有相同的名称和相同或相关的类型。
操作:
命名空间中的两个操作不能具有相同的签名(操作名称、编号、顺序、方向和参数类型)。
类和其他分类器:
命名空间中的两个类不能具有相同的名称,并且不能具有相同或相关的类型。
在这种情况下,两种类型都不是另一种类型是不相关的类型。 也就是说,它们之间不可能存在泛化关系。
这些规则允许建模者在命名方面有一些回旋余地,主要例如重载操作。 尽管在技术上是正确的,但过于频繁地利用它们可能会产生不可读的模型和代码。
需要记住的要点
- 包和包内的其他元素可以标记为公共 (+) 或私有 (-)。
这控制是否可以在其当前 (+) 或 (-) 之外看到。
- 对于具有不同名称的两个元素,它们的名称或类型必须不同。
✓ 对于行为元素,名称和签名(参数的类型、顺序和方向)必须不同。
对于不同的类型,它们不能通过泛化相互关联。
- 对于不直接在包中的元素,包可见性 (~) 允许元素在其容器外看到,但只能看到一个级别。
- 对于不直接在包中的元素,受保护的可见性 (#) 允许元素通过其容器的特殊化。
• # 和 ~ 都不能应用于包
• # 和~ 都不能直接应用于包中的元素。
- 可以直接(非限定)引用外部元素
o 与引用者在同一级别具有冲突名称的元素将隐藏外部元素,强制限定引用
o 具有冲突名称或中间级别的 Element 将隐藏外部 Element,强制限定引用
• 元素的完全限定名称包括PackageName::ElementName。 PackageName:: 链可以根据需要尽可能长。
• 包后面的分隔符是“::”。
• 类后面的分隔符是“.”。