图的目的 组件图的主要目的是显示系统组件间的结构关系。在 UML 1.1 中,一个组件表现了实施项目,如文件和可运行的程序。不幸地,这与组件这个术语更为普遍的用法、指象COM组件这样的东西相冲突。随着时间的推移及UML的连续版本发布, UML 组件已经失去了最初的绝大部分含义。UML 2 正式改变了组件概念的本质意思;在 UML 2 中,组件被认为是独立的,在一个系统或子系统中的封装单位,提供一个或多个接口。虽然 UML 2 规范没有严格地声明它,但是组件是呈现事物的更大的设计单元,这些事物一般将使用可更换的组件来实现。但是,并不象在 UML 1. x中,现在,组件必须有严格的逻辑,设计时构造。主要思想是,你能容易地在你的设计中重用及/或替换一个不同的组件实现,因为一个组件封装了行为,实现了特定接口。1 在以组件为基础的开发(CBD)中,组件图为架构师提供一个开始为解决方案建模的自然形式。组件图允许一个架构师验证系统的必需功能是由组件实现的,这样确保了最终系统将会被接受。 除此之外,组件图对于不同的小组是有用的交流工具。图可以呈现给关键项目发起人及实现人员。通常,当组件图将系统的实现人员连接起来的时候,组件图通常可以使项目发起人感到轻松,因为图展示了对将要被建立的整个系统的早期理解。 开发者发现组件图是有用的,因为组件图给他们提供了将要建立的系统的高层次的架构视图,这将帮助开发者开始建立实现的路标,并决定关于任务分配及(或)增进需求技能。系统管理员发现组件图是有用的,因为他们可以获得将运行于他们系统上的逻辑软件组件的早期视图。虽然系统管理员将无法从图上确定物理设备或物理的可执行程序,但是,他们仍然欢迎组件图,因为它较早地提供了关于组件及其关系的信息(这允许系统管理员轻松地计划后面的工作)。 符号 图 1:这个简单的组件图使用 UML 1.4 符号显示Order System的一般性依赖关系 上述的 UML 1.4 符号在 UML 2 中仍然被支持。然而,UML 1.4 符号集在较大的系统中不能很好地调节。关于这一点的理由是,如同我们在这篇文章的其余部分将会见到一样,UML 2 显著地增强了组件图的符号集。在维持它易于理解的条件下,UML 2 符号能够调节得更好,并且符号集也具有更多的信息。 让我们依照 UML 2 规范一步步建立组件图。 基础 在 UML 2 中,一个组件被画成堆积着可选择小块的一个立着的长方形。UML 2 中,组件的一个高层次的抽象视图,可以用一个长方形建模,包括组件的名字和组件原型的文字和/或图标。组件原型的文本是“«component»”,而组件原型图标是在左边有两个凸出的小长方形的一个大长方形(UML 1.4 中组件的符号元素)。图 2 显示,组件可以用UML 2规范中的三种不同方法表示。 图 2:画组件名字区的不同方法 当在图上画一个组件时,重要的是,你总要包括组件原型文本(在双重尖括号中的那个component,如图 2 所示)和/或图标。理由呢?在 UML 中,没有任何原型分类器的一个长方形被解释为一个类组件。组件原型和/或图标用来区别作为组件元素的长方形。 为组件提供/要求接口建模 图 3:这里额外的区显示Order组件提供和要求的接口。 在图 3 中的Order组件例子中,组件提供了名为 OrderEntry 和 Aclearcase/" target="_blank" >ccountPayable 的接口。此外,组件也要求另外一个组件提供Person接口。3 组件接口建模的其它方法 图 4: 一种可选择的方法(与图3相比):使用接口符号显示组件提供/要求的接口 在这第二种方法中,在末端有一个完整的圆周的接口符号代表组件提供的接口 -- “棒棒糖”是这个接口分类器实现关系符号的速记法。在末端只有半个圆的接口(又称插座)符号代表组件要求的接口(在两种情况下,接口的名字被放置在接口符号本身的附近)。即使图 4 看起来与图 3 有很大的不同,但两个图都提供了相同的信息 -- 例如,Order组件提供两个接口:OrderEntry 和 AccountPayable,而且Order组件 要求 Person接口。 组件关系的建模 图 5:显示Order系统组件如何依赖于其他组件的组件图 图 5 显示,Order系统组件依赖于客户资源库和库存系统组件。注意在图 5 中复制出的接口名 CustomerLookup 和 ProductAccessor。 在这个例子中,这看起来可能是不必要的重复,不过符号确实允许在每个依赖于实现差别的组件中有不同的接口(和不同的名字)(举例来说,一个组件提供一个较小的必需的接口子类)。 子系统 图 6:子系统元素的一个例子 UML 2 规范在如何区别子系统与组件方面相当含糊。从建模的观点,规范并不认为组件与子系统有任何区别。与 UML 1. x 相比较,这个 UML 2 模型歧义是新的。但是有一个理由。在 UML 1. x 中,一个子系统被认为是一个软件包,而且这个软件包符号正对许多 UML 实践者造成困惑;因此,UML 2中把子系统作为特殊的组件,因为这是最多的 UML 1. x 使用者了解它的方式。这一改变确实把模糊引入图中,但是这一模糊更多的是 UML 2 规范中对抗错误的一个现实反射。 到这里,你可能正在抓着头皮并感到疑惑,什么时候该用组件元素,什么时候又该用子系统元素。相当坦率地说,我没有一个直接的答案给你。我可以告诉你,UML 2 规范中说,何时该使用组件或子系统决定于建模者的方法论。我个人很喜欢这个答案,因为它帮助确保UML与方法论相互独立,这在软件开发中将帮助保持它的普遍可使用。 超越基础 显示组件的内部结构 为了显示组件的内部结构,你只需把组件画得比平常大一些并在名字区内放置内部的部分。图 7 显示Store组件的内部结构。 图 7: 这个组件的内部结构由其他组件组成。 使用在图 7 中显示的例子,Store组件提供了 OrderEntry 接口并要求Account接口。Store组件由三个组件组成:Order,Customer和Product组件。注意Store的 OrderEntry 和Account接口符号在组件的边缘上为何有一个方块。这一个方块被称为一个端口。单纯感觉来说,端口提供一种方法,它显示建模组件所 提供/要求 的接口如何与它里面的部分相关联。4 通过使用端口,我们可以从外部实例中分离出Store组件的内部部件。在图 7 中,对于过程而言,OrderEntry 端口代表Order组件的 OrderEntry 接口。同时,内部的Customer组件要求的Account接口被分配到Store组件的必需的Account端口。通过连接Account端口,Store组件内部部件(例如Customer组件)可以有代表执行端口接口的未知外部实体的本地特征。必需的Account接口将会由Store组件的外部组件实现。5 在图 7 中,你可能也注意到了,在内部的组件之间的内部连接与图 5 中显示的那些不同。这是因为内部结构的这些描绘事实是嵌套在分类器(在我们的例子中是一个组件)里的协作图,因为协作图显示分类器中的实体或角色。在内部的组件之间建模的关系以 UML 称为的一个组合连接器表示。一个组合连接器绑定一个组件 提供 的接口到另外的一个组件的 必需 接口。组合连接器用紧紧相连的棒棒糖和插座符号表示。以这种方式画这些组合连接器使棒棒糖和插座成为很容易理解的符号。 结论 组件图也视为软件系统配置图的输入,这将会是本系列后面的文章主题。 脚注 2即使组件是独立的单元,它们仍然可能依赖于其他组件提供的服务。由于这一点,文档化一个组件的必需接口是很有用的。 3图3并不显示Order组件完整的上下文。在一个真实的模型中,OrderEntry,AccountPayable 和Person接口会呈现在系统的模型中。 4事实上,端口适用于任何类型的分类器(例如,一个类或者你的模型中可能会有的其他分类器)。为了使本文简洁,我在组件分类器及它们的使用中提及端口。 5一般来说,当你画一个端口和一个接口之间的依存关系时,依赖方(要求)的接口将会在运行时间内处理所有的处理逻辑。然而,这并不是一种硬性的规定 -- 对于周围的组件(举例来说,我们例子中的Store组件),使用自己的进程逻辑,而不是仅把进程委托给依赖接口,是完全可以接受的。
|