目录
用包把建模元素安排成可作为一个组来处理的较大组块。可以控制这些元素的可见性,使一些元素在包外是可见的,而另一些元素要隐藏在包内。也可以用包表示系统体系结构的不同视图。
狗窝并不复杂:有四面墙,其中一面墙上有一个能让狗通过的洞,还有一个顶棚。在搭一个狗窝时,实际上只需要一小堆木材,仅此而已。
房屋比较复杂。墙、天花板和地板组成了较大的抽象体,称之为房间。甚至可以把这些房间组成更大的组块,如公共区、卧室区、工作区等。这些较大的组可能并不表明它们本身就是与物理房屋有关系的任何事物,而可能只是给出的在逻辑上有关的屋中一些房间的名称,当谈论怎样使用这幢房屋时就使用这些名称。
在UML中,把组织模型的组块称之为包。包是用来把元素组织成组的通用机制。包有助于组织模型中的元素,使得更容易理解它们。包也允许控制对包的内容的访问,从而控制系统体系结构中的接缝。
1、名称
每个包都必须有一个有别于其他包的名称。名称(name)是一个文字串。单独的名称叫做简单名(simple name),限定名(qualified name)是以包所位于的外围包的名称作为前缀的包名。
用双冒号(::)分隔包名。通常在图形中仅显示包名
如图所示。就像类那样,可以绘制用标记值或附加的分栏作为修饰的包,以显示包的细节。
2、元素
包可以拥有其他元素,这些元素可以是类、接口、构件、结点、协作、用况和图,甚至可以是其他包。拥有是一种组成关系,这意味着元素被声明在包中。如果包被撤销了,则元素也要被撤销。一个元素只能被一个包所拥有。
包形成了一个命名空间,这意味着在一个包的语境中同一种元素的名称必须是唯一的。例如,同一个包不能拥有两个名为Queue 的类,
但这种情况是允许的:在 P1 包中有一个名为Queue的类,而在P2包中又有另一个(不同的)名为Queue的类。实际上,类P1::Queue和类P2::Queue是不同的类,这可以由它们各自的路径名区别开来。不同种类的元素可以有相同的名称。
3、可见性
可见性表明一个类对于在同一包内声明的其他类是可见的,但是对于那些在其他包中声明的类是不可见的。通过在类名前加前缀“~”符号来表示包的可见性。
可以通过在元素的名称前面加一个适当的可视符号,来描述包所拥有的元素的可见性。公共的(public)元素用“+”号作为名称的前缀,如上图中的OrderForm。包的各公共部分一同构成包的接口。
像类一样,可以用“#”号或“-”号作为元素的名称的前缀指明元素是受保护的(protected)或私有的(private)。受保护的元素仅对从这个包继承的包可见,私有的元素在这个包外部完全不可见。
4、引入与引出
假设有两个名称分别为A和B的并列的类。因为二者是对等的,A能看见B,B也能看见A,因此它们可以相互依赖。如果二者正好可以组成一个小系统,那么确实就不需要任何种类的包装机制了。
现在设想有几百个这样并列的类,对所能编织的错综复杂的关系网没有任何限制,而且又没有什么办法能理解如此庞大且未加组织的一群类。要使简单的、无约束的访问不至于按比例地增加,这对于大系统而言是一个非常现实的问题。对于这种情景,需要某种受控的包装机制来组织抽象。
现在假设A放在一个包中,B放在另一个包中,而且这两个包是并列的。再假设A和B在各自的包中都被声明为公共的。这是一种非常不同的情形。虽然A和 B都是公共的,但是一个类被另一个包中的类访问需要限定名。然而,如果A的包引入B的包,A就可以直接看见B,但若没有限定名那么B还是看不见A。引入关系把来自目标包中的公共元素添加到进行引入的包的公共命名空间中。
在UML中,用由衍型import修饰的依赖对引入关系建模。通过把抽象包装成有含义的组块,然后用引入关系控制对它们的访问,就能够控制大量抽象的复杂性。
使用了两个衍型,即引入(import)和访问(access)
引入把目标包的内容增加到源包的公共命名空间中,因而不必对名称进行限定。这样就允许
出现原本为保持模型形式良好而必须避免的命名冲突。
访问把目标包的内容增加到了源包的私有命名空间里。所不同的情况是假如第三个包引入源包,就不能再引出已经被引入的目标包元素。
包的公共部分称为它的引出(export)
上图中,包GUI引出两个类,它们是Window和Form。EventHandler没有被GUI引出,EventHandler是包的受保护的部分。
一个包引出的部分,对于那些可见到该包的其他包的内容是可见的。
Policies显式地引入包GUI。因此,对于类GUI::Window和类GUI::Form,包Policies的内容使用简单名Window和Form就能访问它们。然而,由于GUI::EventHandler是受保护的,因此它是不可见的。由于包Server没有引入GUI,Server中的内容必须用限定名才能访问GUI的公共内容,例如,GUI::Window。类似地,由于 Server 中的内容是私有的,GUI 的内容无权访问Server中的任何内容,即使用限定名也不能访问它们。
引入和访问依赖是传递的。在本例中,Client引入 Policies,Policies引入 GUI,所以Client就传递地引入了GUI。因此,Client的内容可以访问Policies的引出,同样可以访问GUI的引出。如果Policies是访问GUI,而不是引入它,则Client不能把GUI中的元素添加到自己的命名空间,但是仍然能通过限定名(如GUI::Window)引用它们。
在类和包之间有一个重要的区别:
类是从问题中或解中所发现的事物的抽象,
包是用于组织模型中的事物的机制。
包在系统运行时不出现,它们完全是组织设计的机制。
例如,上图显示了一组包,它们把信息系统设计视图中的类组织成一个标准的三级体系结构。
包 User Services 中的元素提供了呈现信息和收集数据的可视化界面。
包Data Services中的元素负责维护、访问和修改数据。
包 Business Services中的元素为另两个包的元素搭桥,并包含了管理用户请求(为了执行业务上的任务)的所有类和其他元素,包括支配数据操纵策略的业务规则。
视图是对系统的组织和结构的投影,它关注系统的一个特定方面。
该定义有两个含义:
第一个含义是,可以把系统分解成若干几乎正交的包,每个包表达了一组体系结构上的重大决策。例如,可以有设计视图、交互视图、实现视图、部署视图和用况视图。
第二个含义是,这些包都拥有与相应视图密切相关的所有抽象。例如,模型中的所有构件都属于代表实现视图的包。然而,包可以引用其他包拥有的元素。