
5.2 包图
在UML中,对类进行分组时使用包。大多数面向对象的语言都提供了类似UML包的机制,用于组织及避免类间的名称冲突。例如,Java中的包机制、C#中的命名空间。用户可以使用UML包为这些结构建模。
5.2.1 包
包(Package)是UML中的主要结构,它是一种对模型元素进行成组组织的通用机制。它把语义上相近的可能一起变更的模型元素组织在同一个包中,方便理解复杂的系统,控制系统结构各部分间的接缝。
包是一个概念性的模型管理的图形工具,只在软件的开发过程中存在。包所提供的功能与Windows中的文件夹完全相同,它不仅仅有助于建模人员组织模型中的元素,而且也使建模人员能控制对包中内容的访问。另外,包还具有高内聚、低耦合的特点。
包在UML中用类似文件夹符号表示的模型元素表示,系统中的每个元素都只能为一个包所有,一个包可以嵌套在另外一个包中。下面将从6个方面详细介绍包。
1.包的名称
包的图标是由一个大矩形和其左上角带一个小矩形组成的,每个包都必须有一个与其他包不同的名称。包的名称可以放在左上角的矩形内,也可以放在下面的大矩形中。
通常可以使用一个简单的字符串或路径名作为包的名称。换句话说,包的名称以其外包的包名作为前缀,其中使用两个冒号分隔包的名称。包的名称可以由任意数目的字母、数字和标点符号组成。另外,在包名下可以使用括在花括号中的文字(约束)说明包的性质,如“{abstract}”和“{version}”。如下图所示演示了包的名称。

从上图可以看出:如果包的内容没有被显示在大矩形中,那么可以把该包的名称放在大矩形中;如果包的内容被显示在大矩形中,那么可把该包的名称放在左上角的小矩形中。
注意
在一个包中,不同种类的元素可以有相同的名称,这样在同一个包中对一个类命名为Name,对一个构件也可以命名为Name。但是,为了不造成混乱,最好一个包中的所有元素命名都是唯一的。
2.包所拥有的元素
包只是一种一般性的分组机制,在这个分组机制中可以放置UML类元,如类定义、用例定义、装填定义和类元之间的关系等。在一个包中可以放置3种类型的元素,它们分别如下。
□ 包自身所拥有的元素,如类、接口、组件、节点和用例等。
□ 从另一个包中合并或导入的元素。
□ 另外一个包所访问的元素。
3.包元素的可见性
包的可见性用来控制包外界的元素对包内的元素的访问权限。一个包中的元素在包外的可见性,通过在元素名称前加上一个可见性符号来指示。其可见性包括公有的、私有的和可保护的,它们分别使用“+”“-”和“#”来表示。具体说明如下。
□ + 对所有的包都是可见的。
□ - 只能对该包的子包是可见的。
□ # 对外包是不可见的。
在UML中,包内元素之间的可见性规则如下。
□ 一个包内定义的元素在同一个包内可见。
□ 如果某一个元素在一个包内可见,则它在所有嵌套在该包内的包中可见。
□ 如果一个包和另一个包之间存在<<access>>或<<import>>依赖关系,则后一个包内具有公共可见性的元素在前一个包内可见。
□ 如果一个包是另一个包的子包,则父包内具有公共可见性和保护可见性的元素在子包内可见。
4.包的嵌套
包可以拥有其他包作为包内的元素,子包又可以拥有自己的子包,这样可以构成一个系统的嵌套结构。包的嵌套层数一般以2~3层为宜。嵌套的包与包之间也存在着可见性问题。具体说明如下。
□ 里层包中的元素既能访问其外层包中定义的可见性为公共的元素,也能访问其外层包通过访问或引入依赖而得来的元素。
□ 一个包要访问它的内部包的元素,就与内部包有引入、访问关系或使用限定名。
□ 里层包中的元素的名称会掩盖外层包中的同名元素的名称,在这种情况下需要用限定名引用外层包中的同名元素。
5.划分和组织包
了解过包的知识后,下面主要介绍如何划分和组织包。主要分为4个方面:识别低层包、合并或组织包、标识包中的模型和建立包间的关系。它们的具体说明如下。
□ 识别低层包 每个具有泛化关系或聚合关系的元素位于一个包中;关联密集的类划分到一个包;独立的类暂时作为一个包。
□ 合并或组织包 如果低层包数量过多则把它们合并,或者使用高层包组织它们。组织包的层次时应该遵循两个原则:层次不宜过多和包的划分不是唯一的。
□ 标识包中的模型 对每一个包确定哪些元素在包外是可访问的,把它们标记为公共的。把所有其他的元素标记为受保护的或私有的。
□ 建立包间的关系 根据需要在包之间建立引入依赖、访问依赖或泛化关系。
6.包的用处
包的用处包括以下3部分。
□ 组织相关元素,以便于管理和复用。包是一个命名空间,外部使用要加限定名。
□ 包引入放松了限制,被引入的元素与引入包中的元素可以进行关联,或建立泛化关系。
□ 便于组合可复用的元建模特征,以创建扩展的建模语言,即把被合并包的特征结合到合并包,以定义新的语言。
5.2.2 导入包
当一个包导入另外一个包时,该包里的元素能够使用被导入包里的元素,而不必在使用时通过包名指定其中的元素。例如,当使用某个包中的类时如果未将包导入,则需要使用包名加类名的形式引用指定的类。在导入关系中,被导入的包称作目标包。要在UML中显示导入关系,需要画一条从包连接到目标包的依赖性箭头,再加上字符import,如下图所示。

导入包时,只有目标包中的Public元素是可用的。如下图所示,将security包导入User包后,在User包中只能使用Identity类,而不能使用Creden类。

不仅包中的元素具有可见性,导入关系本身也有可见性。导入可以是公共导入,也可以是私有导入。公共导入意味着被导入的元素在它们导入后的包里具有Public可见性,私有导入则表示被导入的元素在它们导入后的包里具有Private可见性。公共导入仍然使用import表示,私有导入则使用access表示。
在一个包导入另一个包时,其导入的可见性import和access产生的效果是不同的。具有Public可见性的元素在其导入后的包中具有Public可见性,它们的可见性会进一步传递上去,而被私有导入的元素则不会。例如,在下图所示的包模型中,包B公共导入包C并且私有导入包D,因此包B可以使用包C和D中的Public元素,包A公共导入包B,但是包A只能看见包B中的Public元素,以及包C中的Public元素,而不能看见包D中的Public元素。因为包A、B、C之间是公共导入,而包B与C之间是私有导入。

5.2.3 包图概述
包以及类所建立的图形就是包图,使用包图可以将相关元素归入一个系统,一个包中可以包含子包、图表或单个元素。包图经常用于查看包之间的依赖性。因为一个包所依赖的其他包若发生变化,则该包可能会被破坏,所以理解包之间的依赖性对软件的稳定性至关重要。
包图是维护和控制系统总体结构的重要建模工具。对复杂系统进行建模时,经常需要处理大量的类、接口、组件、节点等元素,这时有必要对它们进行分组。把语义相近并倾向于同一变化的元素组织起来加入同一个包中,以便于理解和处理整个模型。
包组织UML元素,如类。包的内容可以画在包内,也可以画在包外,并以线条连接。包图可以应用在任何一种UML图上,如下图所示演示了包图的两种表示方法。

再如,下图所示演示了包图的一个简单示例。

注意
包图几乎可以组织所有UML元素,而不仅仅是类。例如,包可以对用例进行分组。另外,在包中也可以包含其他包,在企业级应用程序中经常见到深层的嵌套包。例如,编程语言Java和C#都提供了嵌套包。
1.包图中包的标准构造型
UML的所有扩展机制都适用于包,建模人员可用标记值为包增加新的特性,也可用衍型给出新类型的包。UML定义了5种应用于包的标准衍型,它们也叫作包的构造型。其具体说明如下。
□ Facade 说明包仅仅是其他一些包的视图,只包含对另外一个包所拥有的模型元素的引用,只用作另外一个包的部分内容的公共视图。
□ Framework 说明一个包代表模型架构。
□ Stub 说明一个包是另一个包的公共内容的服务代理。
□ Subsystem 说明一个包代表系统模型的一个独立部分,即子系统。
□ System 说明一个包代表系统模型。
2.包图的作用
包图的作用如下所示。
□ 描述需求的高阶概述(用例图)。
□ 描述设计的高阶概述(类图)。
□ 在逻辑上把一个复杂的图模块化。
□ 组织源代码(命名空间)。
3.类包图
包图可以由任何一种UML构成,通常是UML用例图或类图,把UML类图组织到包图中可称作类包图。创建类包图可以在逻辑组织上设计系统,但是需要采用以下规则。
□ 把一个框架的所有类放置到相同的包中,形成一个系统包。
□ 把具有继承关系的类放在相同的包中,比如通信包。
□ 将彼此间有聚合或组合关系的类放在同一个包中。
□ 将彼此合作频繁的类放在一个包中。
如下图所示演示了类包图的一个实例。

4.用例包图
用例最主要的需求是artifact,用例的目的是描述系统需求,而用例包图的目的则是用来组织使用需求。用例包图的组织规则如下。
□ 把关联的用例放在一起:包含(Included)、扩展(Extend)或泛化(Generalization)用例放在同一个包中。
□ 组织用例应该以主要角色的需求为基础。
在用例包图中可以包含角色,这有助于把包放在上下文中理解,这样包图就会更加容易为读者所理解。另外用户也可以水平地排列用例包图。
5.构建包图的注意事项
包图的使用非常简单,但是要注意以下几个方面。
(1)包的命名要简单,要具有描述性。
(2)使用的目的是为了简化UML图形表示。
(3)包应该连贯。
(4)避免包间的循环依赖。
(5)包依赖应该反映内部关系。
5.2.4 包之间的关系
包与包之间最常用的关系是依赖关系与泛化关系,下面将详细介绍它们的相关知识。
1.依赖关系
有时一个包中的类需要用到另一个包中的类,这就造成包之间的依赖性,建模人员必须使用<<access>>或<<import>>的依赖。<<import>>的依赖也可以叫作输入依赖或引入依赖。<<access>>叫作访问依赖,它的表示方法是在虚箭线上标有构造型<<access>>,箭头从输入方的包指向输出方的包。如下图所示演示了一个关于包与包之间的依赖关系。

根据包内元素可见性的规则,从上图中可以得出以下几个常见的结论。
由于A所在的包U嵌套在C所在的包Y中,而Y所在的包又嵌套在E所在的包X中,因此A能够看见C和E。
由于包Y有一个指向包Z的<<access>>依赖,而A又嵌套在包Y中,因此A和C都能够看见D。
由于D和E是在包V的外围包中定义的,因此包B和F能够看见D和E。
由于B和F的外围包X具有一条指向包Y的<<access>>依赖,因此B和F都能够看见C。
虽然<<access>>依赖关系和<<import>>依赖关系都可以用来描述客户包对提供者包的访问关系,并且都不能进行传递,但是它们之间还是有细微的区别的:<<import>>依赖关系使提供者包中的内容增加到客户包中,但是<<access>>依赖关系不会增加客户包中的内容。因此,在使用<<import>>关系时,建模人员应该注意不要让客户包和提供者包中元素的名称冲突。
包之间的复杂依赖会导致软件脆弱,因为一个包里的改变会造成依赖它的其他包被破坏。如果包之间的依赖性具有循环关系,应以各种方式切断循环。
2.泛化关系
泛化关系是表达事物的一般和特殊的关系,如果两个包之间有泛化关系,意指其中的特殊性包必须遵循一般性包的接口。包与包之间的泛化关系和类间的泛化关系很相似,因此涉及泛化关系的包也像类那样遵循可替换性原则。如下图所示演示了包间的基本泛化关系。

5.2.5 包图和类图的区别
包图是在UML中用类似于文件夹的符号表示的模型元素的组合,系统中的每个元素都只能为一个包所有。到目前为止,用户已了解了包图和类图的相关知识,而下表列出了包图和类图的主要区别。
