|
级别: 初级 Donald Bell, IBM 全球服务, IBM 2004 年 2 月 01 日 回顾20世纪晚期--准确地说是1997年,OMG组织(Object Management Group对象管理组织)发布了统一建模语言(Unified Modeling Language,UML)。UML的目标之一就是为开发团队提供标准通用的设计语言来开发和构建计算机应用。UML提出了一套IT专业人员期待多年的统一的标准建模符号。通过使用UML,这些人员能够阅读和交流系统架构和设计规划--就像建筑工人多年来所使用的建筑设计图一样。 到了21世纪--准确地说是2003年,UML已经获得了业界的认同。在我所见过的专业人员的简历中,75%都声称具备UML的知识。然而,在同绝大多数求职人员面谈之后,可以明显地看出他们并不真正了解UML。通常地,他们将UML用作一个术语,或对UML一知半解。大家对UML缺乏理解的这种状况,促进我撰写这篇关于UML 1.4的快速入门文章。当阅读完本文时,您还不具备足够的知识可以在简历上声称自己掌握了UML,但是您已具有了进一步钻研该语言的良好起点。
既然UML不是一种方法学,它就不需要任何正式的工作产品(即IBM Rational Unified Process?术语中所定义的"工件")。而且它还提供了多种类型的模型描述图(diagram),当在某种给定的方法学中使用这些图时,它使得开发中的应用程序的更易理解。UML的内涵远不只是这些模型描述图,但是对于入门来说,这些图对这门语言及其用法背后的基本原理提供了很好的介绍。通过把标准的UML图放进您的工作产品中,精通UML的人员就更加容易加入您的项目并迅速进入角色。最常用的UML图包括:用例图、类图、序列图、状态图、活动图、组件图和部署图。 深入讨论每类图的细节问题已超出了这篇入门文章的范围。因此,下面仅给出了每类图的简要说明,更详细的信息将在以后的文章中探讨。
图1:示例用例图 图字(从上到下):CD销售系统;查看乐队CD的销售统计;乐队经理;查看Billboard 200排行榜报告;唱片经理;查看特定CD的销售统计;检索最新的Billboard 200排行榜报告;排行榜报告服务 用例图通常用于表达系统或者系统范畴的高级功能。如图1所示,可以很容易看出该系统所提供的功能。这个系统允许乐队经理查看乐队CD的销售统计报告以及Billboard 200排行榜报告。它也允许唱片经理查看特定CD的销售统计报告和这些CD在Billboard 200排行榜的报告。这个图还告诉我们,系统将通过一个名为"排行榜报告服务"的外部系统提供Billboard排行榜报告。 此外,在用例图中,没有列出的用例表明了该系统不能完成的功能。例如,它不能提供给乐队经理收听Billboard 200上不同专辑中的歌曲的途径 -- 也就是说,系统没有引用一个叫做"收听Billboard 200上的歌曲"的用例。这种缺少不是一件小事。在用例图中提供清楚的、简要的用例描述,项目赞助商就很容易看出系统是否提供了必须的功能。
类在类图上使用包含三个部分的矩形来描述,如图2所示。最上面的部分显示类的名称,中间部分包含类的属性,最下面的部分包含类的操作(或者说"方法")。 图2:类图中的示例类对象 根据我的经验,几乎每个开发人员都知道这个类图是什么,但是我发现大多数程序员都不能正确地描述类的关系。对于像图3这样的类图,您应该使用带有顶点指向父类的箭头的线段来绘制继承关系1,并且箭头应该是一个完全的三角形。如果两个类都彼此知道对方,则应该使用实线来表示关联关系;如果只有其中一个类知道该关联关系,则使用开箭头表示。 图3:一个完整的类图,包括了图2所示的类对象 在图3中,我们同时看到了继承关系和两个关联关系。CDSalesReport类继承自Report类。一个CDSalesReport类与一个CD类关联,但是CD类并不知道关于CDSalesReport类的任何信息。CD类和Band类都彼此知道对方,两个类彼此都可以与一个或者多个对方类相关联。 一个类图可以整合其他许多概念,这将在本系列文章的后续文章中介绍。
序列图有两个维度:垂直维度以发生的时间顺序显示消息/调用的序列;水平维度显示消息被发送到的对象实例。 序列图的绘制非常简单。横跨图的顶部,每个框(参见图4)表示每个类的实例(对象)。在框中,类实例名称和类名称之间用空格/冒号/空格来分隔,例如,myReportGenerator : ReportGenerator。如果某个类实例向另一个类实例发送一条消息,则绘制一条具有指向接收类实例的开箭头的连线,并把消息/方法的名称放在连线上面。对于某些特别重要的消息,您可以绘制一条具有指向发起类实例的开箭头的虚线,将返回值标注在虚线上。就我而言,我总喜欢绘制出包括返回值的虚线,这些额外的信息可以使得序列图更易于阅读。 阅读序列图也非常简单。从左上角启动序列的"驱动"类实例开始,然后顺着每条消息往下阅读。记住:虽然图4所示的例子序列图显示了每条被发送消息的返回消息,但这只是可选的。 图4:一个示例序列图 通过阅读图4中的示例序列图,您可以明白如何创建一个CD销售报告(CD Sales Report)。其中的aServlet对象表示驱动类实例。aServlet向名为gen的ReportGenerator类实例发送一条消息。该消息被标为generateCDSalesReport,表示ReportGenerator对象实现了这个消息处理程序。进一步理解可发现,generateCDSalesReport消息标签在括号中包括了一个cdId,表明aServlet随该消息传递一个名为cdId的参数。当gen实例接收到一条generateCDSalesReport消息时,它会接着调用CDSalesReport类,并返回一个aCDReport的实例。然后gen实例对返回的aCDReport实例进行调用,在每次消息调用时向它传递参数。在该序列的结尾,gen实例向它的调用者aServlet返回一个aCDReport。 请注意:图4中的序列图相对于典型的序列图来说太详细了。然而,我认为它才是足够易于理解的,并且它显示了如何表示嵌套的调用。对于初级开发人员来说,有时把一个序列分解到这种详细程度是很有必要的,这有助于他们理解相关的内容。
如图5所示,状态图的符号集包括5个基本元素:初始起点,它使用实心圆来绘制;状态之间的转换,它使用具有开箭头的线段来绘制;状态,它使用圆角矩形来绘制;判断点,它使用空心圆来绘制;以及一个或者多个终止点,它们使用内部包含实心圆的圆来绘制。要绘制状态图,首先绘制起点和一条指向该类的初始状态的转换线段。状态本身可以在图上的任意位置绘制,然后只需使用状态转换线条将它们连接起来。 图5:显示类通过某个功能系统的各种状态的状态图 图5中的状态图显示了它们可以表达的一些潜在信息。例如,从中可以看出贷款处理系统最初处于Loan Application状态。当批准前(pre-approval)过程完成时,根据该过程的结果,或者转到Loan Pre-approved状态,或者转到Loan Rejected状态。这个判断(它是在转换过程期间做出的)使用一个判断点来表示--即转换线条间的空心圆。通过该状态图可知,如果没有经过Loan Closing状态,贷款不可能从Loan Pre-Approved状态进入Loan in Maintenance状态。而且,所有贷款都将结束于Loan Rejected或者Loan in Maintenance状态。
活动图的符号集与状态图中使用的符号集类似。像状态图一样,活动图也从一个连接到初始活动的实心圆开始。活动是通过一个圆角矩形(活动的名称包含在其内)来表示的。活动可以通过转换线段连接到其他活动,或者连接到判断点,这些判断点连接到由判断点的条件所保护的不同活动。结束过程的活动连接到一个终止点(就像在状态图中一样)。作为一种选择,活动可以分组为泳道(swimlane),泳道用于表示实际执行活动的对象,如图6所示。 图6:活动图,具有两个泳道,表示两个对象的活动控制:乐队经理,以及报告工具 图字(沿箭头方向):乐队经理;报告工具;选择"查看乐队的销售报告";检索该乐队经理所管理的乐队;显示报告条件选择屏幕;选择要查看其销售报告的乐队;从销售数据库检索销售数据;显示销售报告。 该活动图中有两个泳道,因为有两个对象控制着各自的活动:乐队经理和报告工具。整个过程首先从乐队经理选择查看他的乐队销售报告开始。然后报告工具检索并显示他管理的所有乐队,并要求他从中选择一个乐队。在乐队经理选择一个乐队之后,报告工具就检索销售信息并显示销售报告。该活动图表明,显示报告是整个过程中的最后一步。
组件图的建模最适合通过例子来描述。图7显示了4个组件:Reporting Tool、Billboard Service、Servlet 2.2 API和JDBC API。从Reporting Tool组件指向Billboard Service、Servlet 2.2 API和JDBC API组件的带箭头的线段,表示Reporting Tool依赖于那三个组件。 图7:组件图显示了系统中各种软件组件的依赖关系
部署图中的符号包括组件图中所使用的符号元素,另外还增加了几个符号,包括节点的概念。一个节点可以代表一台物理机器,或代表一个虚拟机器节点(例如,一个大型机节点)。要对节点进行建模,只需绘制一个三维立方体,节点的名称位于立方体的顶部。所使用的命名约定与序列图中相同:[实例名称] : [实例类型](例如,"w3reporting.myco.com : Application Server")。 图8:部署图。由于Reporting Tool组件绘制在IBM WebSphere内部,后者又绘制在节点w3.reporting.myco.com内部,因而我们知道,用户将通过运行在本地机器上的浏览器来访问Reporting Tool,浏览器通过公司intranet上的HTTP协议与Reporting Tool建立连接。 图8中的部署图表明,用户使用运行在本地机器上的浏览器访问Reporting Tool,并通过公司intranet上的HTTP协议连接到Reporting Tool组件。这个工具实际运行在名为w3reporting.myco.com的Application Server上。这个图还表明Reporting Tool组件绘制在IBM WebSphere内部,后者又绘制在w3.reporting.myco.com节点内部。Reporting Tool使用Java语言通过IBM DB2数据库的JDBC接口连接到它的报告数据库上,然后该接口又使用本地DB2通信方式,与运行在名为db1.myco.com的服务器上实际的DB2数据库通信。除了与报告数据库通信外,Report Tool组件还通过HTTPS上的SOAP与Billboard Service进行通信。
1 delayFlight没有返回值,因为我作出了设计决定,不要返回值。有一点可以争论的是,延迟操作应该返回新的到达时间,而且,如果是这种情形,操作属性将显示为 2可能看起来很奇怪, BankAccount 类不知道 OverdrawnAccountsReport 类。这个建模使报表类可以知道它们报告的业务类,但是业务类不知道它们正在被报告。这解开两个对象的耦合,并因此使系统变得更能适应变化。 3 软件包对于组织你的模型类是庞大的,但是记住重要的一点是,你的类图应该是关于建模系统的容易交流的信息。在你的软件包有许多类的情况下,最好使用多个主题类图,而不是仅仅产生一个大的类图。 4 要理解重要一点,当我说“所有的那些成员”时,我仅仅意味着在当前图中的类将显示出来。显示一个有内容的软件包的图,不需要显示它的所有内容。它可以依照一些准则,显示包含元素的子集,这个准则就是并非所有的软件包分类器都是必需的。 5 当画一个类图时,在 UML 规范中,全部要做的只是把类放入长方形的顶部区域,而你同理处理接口;然而,UML 规范认为,在这个区域放置“class”文本是可选的,如果类没有显示,那么它应该被假设。
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 在完全建模系统中,对象(类的实例)也将会在系统的类图中建模。
2 当阅读这个序列图时,假定分析师登录进入系统之内。
3 请注意,附着在不同的变体操作元上的、两个或更多的约束条件式的确可能同时是真,但是实际最多只有一个操作元将会在运行时发生(那种情况下变体的“wins”没有按照 UML 标准定义)。
4 虽然操作元看起来非常象公路上的小路,但是我特别不叫它们小路。泳道是在活动图上使用的 UML 符号。请参考The Rational Edge 早期关于 活动图 的文章。
5 通常,附上约束的生命线是拥有包含在约束表达式中的变量的生命线。
6 关于选择项组合碎片,循环组合碎片不需要在它上放置一个约束条件。
7 可能重用任何类型的序列图(举例来说,程序或业务)。我只是发现开发者更喜欢按功能分解他们的图。
|
级别: 初级 Donald Bell, IBM 全球服务, IBM 2005 年 2 月 15 日 来自 Rational Edge:这篇文章介绍组件图,一个在新的统一建模语言 2.0中规定的结构图。
组件图的主要目的是显示系统组件间的结构关系。在 UML 1.1 中,一个组件表现了实施项目,如文件和可运行的程序。不幸地,这与组件这个术语更为普遍的用法、指象COM组件这样的东西相冲突。随着时间的推移及UML的连续版本发布, UML 组件已经失去了最初的绝大部分含义。UML 2 正式改变了组件概念的本质意思;在 UML 2 中,组件被认为是独立的,在一个系统或子系统中的封装单位,提供一个或多个接口。虽然 UML 2 规范没有严格地声明它,但是组件是呈现事物的更大的设计单元,这些事物一般将使用可更换的组件来实现。但是,并不象在 UML 1. x中,现在,组件必须有严格的逻辑,设计时构造。主要思想是,你能容易地在你的设计中重用及/或替换一个不同的组件实现,因为一个组件封装了行为,实现了特定接口。 1
在以组件为基础的开发(CBD)中,组件图为架构师提供一个开始为解决方案建模的自然形式。组件图允许一个架构师验证系统的必需功能是由组件实现的,这样确保了最终系统将会被接受。 除此之外,组件图对于不同的小组是有用的交流工具。图可以呈现给关键项目发起人及实现人员。通常,当组件图将系统的实现人员连接起来的时候,组件图通常可以使项目发起人感到轻松,因为图展示了对将要被建立的整个系统的早期理解。 开发者发现组件图是有用的,因为组件图给他们提供了将要建立的系统的高层次的架构视图,这将帮助开发者开始建立实现的路标,并决定关于任务分配及(或)增进需求技能。系统管理员发现组件图是有用的,因为他们可以获得将运行于他们系统上的逻辑软件组件的早期视图。虽然系统管理员将无法从图上确定物理设备或物理的可执行程序,但是,他们仍然欢迎组件图,因为它较早地提供了关于组件及其关系的信息(这允许系统管理员轻松地计划后面的工作)。
在现在,组件图符号集使它成为最容易画的 UML 图之一。图 1 显示了一个使用前 UML 1.4 符号的简单的组件图;这个例子显示两个组件之间的关系:一个使用了Inventory System组件的Order System组件。正如你所能见到的,在UML 1.4 中,用一个大方块,并且在它的左边有两个凸出的小方块,来表示组件。 图 1:这个简单的组件图使用 UML 1.4 符号显示Order System的一般性依赖关系 上述的 UML 1.4 符号在 UML 2 中仍然被支持。然而,UML 1.4 符号集在较大的系统中不能很好地调节。关于这一点的理由是,如同我们在这篇文章的其余部分将会见到一样,UML 2 显著地增强了组件图的符号集。在维持它易于理解的条件下,UML 2 符号能够调节得更好,并且符号集也具有更多的信息。 让我们依照 UML 2 规范一步步建立组件图。
现在,在 UML 2 中画一个组件很类似于在一个类图上画一个类。事实上,在 UML 2 中,一个组件仅仅是类概念的一个特殊版本。这意味着适用于类分类器的符号规则也适用于组件分类器。(如果你已经读了并理解了我以前的关于大体上的结构图和类图细节的文章 [http:// www. ibm.com/developerworks/cn/rational/rationaledge/content/feb05/bell/index.shtml],你就会很易理解组件图)。 在 UML 2 中,一个组件被画成堆积着可选择小块的一个立着的长方形。UML 2 中,组件的一个高层次的抽象视图,可以用一个长方形建模,包括组件的名字和组件原型的文字和/或图标。组件原型的文本是“«component»”,而组件原型图标是在左边有两个凸出的小长方形的一个大长方形(UML 1.4 中组件的符号元素)。图 2 显示,组件可以用UML 2规范中的三种不同方法表示。 图 2:画组件名字区的不同方法 当在图上画一个组件时,重要的是,你总要包括组件原型文本(在双重尖括号中的那个component,如图 2 所示)和/或图标。理由呢?在 UML 中,没有任何原型分类器的一个长方形被解释为一个类组件。组件原型和/或图标用来区别作为组件元素的长方形。 在图 2 中所画的Order组件表现了所有有效的符号元素;然而,一个典型的组件图包括更多的信息。一个组件元素可以在名字区下面附加额外的区。如前面所提到的,一个组件是提供一个或更多公共接口的独立单元。提供的接口代表了组件提供给它的用户/客户的服务的正式契约。图 3 显示了Order组件有第二个区,用来表示Order组件提供和要求的接口。 2 图 3:这里额外的区显示Order组件提供和要求的接口。 在图 3 中的Order组件例子中,组件提供了名为 OrderEntry 和 AccountPayable 的接口。此外,组件也要求另外一个组件提供Person接口。 3 UML 2 也引入另外一种方法来显示组件提供并要求的接口。这个方法是建立一个里面有组件名的大长方形,并在长方形的外面放置在 UML 2 规范中称为接口符号的东西。这第二种方法在图 4 中举例说明。 图 4: 一种可选择的方法(与图3相比):使用接口符号显示组件提供/要求的接口 在这第二种方法中,在末端有一个完整的圆周的接口符号代表组件提供的接口 -- “棒棒糖”是这个接口分类器实现关系符号的速记法。在末端只有半个圆的接口(又称插座)符号代表组件要求的接口(在两种情况下,接口的名字被放置在接口符号本身的附近)。即使图 4 看起来与图 3 有很大的不同,但两个图都提供了相同的信息 -- 例如,Order组件提供两个接口:OrderEntry 和 AccountPayable,而且Order组件 要求 Person接口。 当表现组件与其他的组件的关系时,棒棒糖和插座符号也必须包括一支依存箭头(如类图中所用的)。在有棒棒糖和插座的组件图上,注意,依存箭从强烈的(要求的)插座引出,并且它的箭头指向供应者的棒棒糖,如图 5 所示。 图 5:显示Order系统组件如何依赖于其他组件的组件图 图 5 显示,Order系统组件依赖于客户资源库和库存系统组件。注意在图 5 中复制出的接口名 CustomerLookup 和 ProductAccessor。 在这个例子中,这看起来可能是不必要的重复,不过符号确实允许在每个依赖于实现差别的组件中有不同的接口(和不同的名字)(举例来说,一个组件提供一个较小的必需的接口子类)。 在 UML 2 中,子系统分类器是组件分类器的一个特别版本。因为这一点,子系统符号元素象组件符号元素一样继承所有的组件符号集规则。唯一的差别是,一个子系统符号元素由subsystem关键字代替了component,如图 6 所示。 图 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 称为的一个组合连接器表示。一个组合连接器绑定一个组件 提供 的接口到另外的一个组件的 必需 接口。组合连接器用紧紧相连的棒棒糖和插座符号表示。以这种方式画这些组合连接器使棒棒糖和插座成为很容易理解的符号。
组件图经常是一个架构师在项目的初期就建立的非常重要的图。然而,组件图的有用性跨越了系统的寿命。组件图是无价的,因为它们模型化和文档化了一个系统的架构。因为组件图文档化了系统的架构,开发者和系统可能的系统管理员会发现这一工作的关键产品有助于他们理解系统。 组件图也视为软件系统配置图的输入,这将会是本系列后面的文章主题。 | ||||||||||||||||||||||||||||||||||||||||||
1在UML1.x 中称为组件的实际项目,在 UML 2 中称为产物。一个产物是一个物理单位,象一个文件,可运行的程序,脚本,数据库等等。只有一种产物依赖于实际的节点;类和组件没有“位置”。然而,一个产物可能显示组件和其他的分类器(例如类)。一个单一的组件可能通过多重产物显示,它们可能是在相同的或不同的节点上,因此,一个单一的组件可以间接地在多重节点上被实现。
2即使组件是独立的单元,它们仍然可能依赖于其他组件提供的服务。由于这一点,文档化一个组件的必需接口是很有用的。
3图3并不显示Order组件完整的上下文。在一个真实的模型中,OrderEntry,AccountPayable 和Person接口会呈现在系统的模型中。
4事实上,端口适用于任何类型的分类器(例如,一个类或者你的模型中可能会有的其他分类器)。为了使本文简洁,我在组件分类器及它们的使用中提及端口。
5一般来说,当你画一个端口和一个接口之间的依存关系时,依赖方(要求)的接口将会在运行时间内处理所有的处理逻辑。然而,这并不是一种硬性的规定 -- 对于周围的组件(举例来说,我们例子中的Store组件),使用自己的进程逻辑,而不是仅把进程委托给依赖接口,是完全可以接受的。
|
级别: 初级
Davor Gornik, 高级工程师
2004 年 11 月 01 日
软件行业中最常被误解的一个术语实际上是我们非常熟悉的一个:实体关系(ER)。这是因为我们经常缺少一种能被开发团队的所有成员理解的共同定义。我们假定团队的每个成员都对与 ER 和 ER 建模相关的方法学、语法和机制(mechanics)有着同样清楚的理解。
软件行业中最常被误解的一个术语实际上是我们非常熟悉的一个:实体关系(ER)。这是因为我们经常缺少一种能被开发团队的所有成员理解的共同定义。我们假定团队的每个成员都对与 ER 和 ER 建模相关的方法学、语法和机制(mechanics)有着同样清楚的理解。
ER 建模本身定义了在基于信息的系统的分析和设计中用到的方法。数据库设计者通常使用该方法来收集需求,并定义数据库系统的构架。该方法的输出是实体类型、关系类型和约束条件的清单。
不幸的是,ER 建模没有为 ER 图的表示定义图解语法。数据库团队经常单独使用表示法,并且将 ER 建模限制在关系数据库设计的范围内。我们需要一种能让整个系统开发团队的成员获得更广泛理解的表示法。
统一建模语言(UML)是一种分析人员和软件开发人员广泛使用的语言,特别适合 ER 图的图形化表示。通过使用 UML,开发团队受益匪浅,这些获益包括团队成员间的交流更加简单,由于该语言是基于元模型的因而更容易与知识库集成,标准化输入/输出格式(XMI)的使用,应用建模和数据建模的普遍使用,从分析到实施再到部署的统一表示,以及规格说明书的完整性。
本白皮书定义了 ER 建模的核心概念,并解释了开发团队如何能够利用 UML 开发 ER 模型。
|
ER 建模基于工件,可以是物理工件(比如 Product 或 Employee)的表示或者工件(比如 Order 或 Delivery)之间事务的表示。每个工件都包含关于自身的信息。ER 建模还专注于工件间的关系。这些关系可以是二元的(连接两个工件),也可以是三元的(在几个工件之间)。
ER 建模的四个必要元素是:
- 实体类型
- 属性
- 关系类型
- 关系属性
实体类型是具有相同的结构并在企业内部独立存在的一组工件。Employees 或 Products 就是实体类型的例子。
工件的一次出现就是一个实体。虽然实体类型描述了结构,但是实体本身标识了单个实例以及该实例的所有数据。Employee Joe Ward 就是 Employees 实体的一个例子。
图 1 实体类型 Employees 和实体 Employees Joe Ward
实体类型的结构是用属性定义的。属性可看作实体类型的特征。Employee 的属性可能有姓名、住址、社会安全号码、出生日期、参加工作日期以及职务等。
实体通过属性值来互相区分。由于实体的属性可能有相同的值,如果这样我们就不能区分某些特定的实体。因此,我们必须保证特定实体的属性值与其他实体的属性值不同。各个 Employee 都有一个唯一的姓名和社会安全号码属性组合。
Employee 的属性值的一个例子是:Joe Ward,地址为 34 Main Road, Redmond, WA, 98053,社会安全号码为 555-32-2222,出生于 1971 年 9 月 7 日,2001 年十月 1 日加入公司,是家电服务工程师。
图 2 实体类型 Employee 的属性以及实体 Employee Joe Ward 的属性值
实体类型描述了独立工件,而关系类型描述了实体类型间有意义的关联。更准确的说,关系类型描述了参与该关系的实体类型的实体可以构建一个有意义的关联。实体间实际发生的关联被称为一种关系。
有一点我们必须理解:尽管我们已经定义了一种关系类型,但是这并不意味着每一对实体都构建了一种关系。关系类型规定了发生关系的类型。
关系类型的一个例子是 Employee 拥有 Product。在该例中,关系类型是 Owns。关系本身是:Employee Joe Ward 拥有一种产品--一部编号 320 TS 03880 的黄色电话机。
图 3 雇员 Joe Ward 和序号 320 TS 03880 的产品之间的拥有关系类型和拥有关系
也有可能有一位名叫 Martin Weber 的雇员就没有拥有电话机。
关系类型还可以包含属性。比如,Employee 和 Product 间的关系类型 Services 可以包含属性 Date 和 Status,标识了服务的日期以及服务之后产品的状态。
当在具体发生的服务中实现关系时,该关系的属性值就被设置。关系的含义可能是:Joe Ward 在 2002 年 7 月 3 日为序号是 0462834 DF 4的黑色饮水机提供维修服务,并且使其建立了良好的工作状态。
图 4 services 关系类型的属性,以及 Joe Ward 为序号 0462834 DF 4的产品提供服务的关系的属性
ER 模型中的实体、关系和属性建立了一些定义企业结构的限制。该结构受被称为"约束"的规则所限制。比如,一个雇员不可能与 100 多位客户打交道。或者说,每个雇员必须与某一个恰当的部门关联。
基数(Cardinality)
每个指定的关系类型都定义了在所有参与实体之间建立关系的可能性。大多数情况下,这不是必需的。比如,并非所有 Employee 都拥有全部 Product。
关系是双向的,连接了两种实体类型(Employees 和 Products)或者扮演两个不同角色(作为经理的 Employee 和作为下属的 Employee)的同一实体类型。关系还可以是多向的,连接两个以上的实体类型。连接一个雇员、一个客户和两部话机的一次电话呼叫就是多向关系的一个例子。不管是哪种情况,每个实体类型都指定了针对该关系类型的基数。
通过每个实体最大的关系数目指定了最简单的基数。如果只有一个部门参与和一个雇员关联的关系,那么我们在连接器上写一个 1。这意味着 Joe Ward 必须与一个并且只能是一个部门关联。
其他的基数还有 Not Specified 或 Specified By a Variable。Not Specified 基数没有限制。基数 Specified By a Variable (大部分为M 或N)同样没有基数限制。
当一个关系中的参与实体的上限和下限不同时,我们为上限和下限指定一对值,用括号括起来,之间用逗号分开,如(M,N)。根据上限的不同,可选的关系可以用(0,1)或(0,N)表示。
比如,足球队和球员的关系为(11,18)。实体 Redmond Lions 足球队与实体类型球员之间建立了一种关系,它由 Joe Coplen、David Archer、John Good、Kevin Hale、Ivan Komashinsky、Steven Cooper、Andrew Bliven、Art Lounsbery、Chad Beery、Randall DuBois、Ron Baghai、Lance Delo、Tito Magobet、Curtis Hrischuk 和 Ian Leslie 组成。
图 5 足球队和球员之间的关系规定这种关系只有在球队球员在 11 到 18 之间时才有效
图 6 有效的关系是 Redmond Lions 足球俱乐部和 15 名球员之间的队员
足球比赛中经常有队员由于不当的行为或者犯规而领到黄牌或红牌。它们用实体类型 Cards 来表示。Cards 实体类型与基数为(0,N)的球员构建了一种 Received 关系。这意味着球员 David Archer 可能与三个 Card 实体有着 Received 关系,而 Lance Delo 却一个也没有。
图 7 实体类型球员可能收到 0 个或者任意数目的 Card 实体类型:David Archer 收到 3 张牌,而 Lance Delo 一张牌也没有收到。
依赖关系
依赖关系指的如果在一个关系中指定的其中一个实体不存在,那么另一个实体也没有存在的意义。当依赖型实体(子类型)的各个实体依赖于超类型中对应父实体存在时,则一个实体类型依赖于另一个实体类型。
必须通过显式地定义一个下限不为 0 的基数,或者定义个一个不为 0 的固定基数,来指定一个强制的依赖关系。实体类型结婚证就是两个实体间依赖关系的一个例子,其中结婚证依赖于实体类型人。关系是结婚,并且结婚证和两个人之间具有固定的依赖关系。
比如,实体结婚证 352647003 与实体 Joe Ward 和 Melinda Bell 具有固定的依赖关系。这意味着如果 Melinda Bell 或 Joe Ward 脱离该关系,那么至少从数据的角度来说,结婚证352647003就已经失效。
图 8 建立在实体类型人之上的依赖性实体类型结婚证,以及实体结婚证 352647003 与 Melinda Bell 和 Joe Ward 间的依赖关系
核心 ER 模型只定义了实体类型间的基本关系。虽然利用基本的实体和关系就可以很容易地表示商业机构中的大多数简单数据结构,但是技术应用要求基于实体类型间的相似点和不同点的更复杂的结构。
特化和泛化
特化和泛化的目的在于重用与实体类型关联的属性和行为。
特化用于定义代表一个大型实体类型的一个特定部分的实体类型。特化后的实体类型从父实体类型继承了结构和行为,比如业务规则。然而,虽然特化后的实体类型扩展了父结构或类型,但是这决不是说它小于父类型。
比如,Employee 是实体类型 Person 的一个特化,它需要实体类型 Person 的所有属性和关系。另外还有一种叫做 Customer 的实体类型,它也是实体类型 Person 的一个特化。这两种实体类型都具有 Person 的属性,它们被看作 Employee 或 Customer 的属性。因此在我们看 Customer 时,看到的是在实体类型 Person 和实体类型 Customer 中指定的所有属性。
泛化是正好相反的工作流。泛化实体类型(或者父类型)代表所有子类型的共同结构和行为,并且包含了来自子实体类型的所有共同属性。子实体类型具有父属性的所有内容,并且还拥有自己的属性。
泛化过程找出共同结构并在父实体类型中抽象出来。父实体类型通常在比较实体类型和简化模型时的重构阶段被找到。
虽然泛化仅利用面向对象或者对象关系数据库就可以直接实现,但是泛化也可以通过使用外键的任何关系数据库直接实现。
图 9 实体类型 Customer 和实体类型 Employee 被泛化为人实体类型;反向过程就是特化
分类(Categorization)
特化是在实体上完成的,而分类则定义了关系类型上的约束条件。大多数情况下,分类是排他性的,这意味着根据实体状态的不同,一个实体要么参与关系 A 要么参与关系 B。该状态可能是一个属性值(另一种关系的存在),或是某些外部状态。
分类不改变实体的属性。它需要数据访问和操纵,来考虑分类中指定的约束条件。
交通工具就是分类的一个好例子。根据交通工具种类的不同,我们需要构建不同的关系。对于卡车,我们需要货物信息,而对于公共汽车,我们需要乘客姓名。这些信息将被用于不同的关系中,以便为这些关系提供有意义的上下文。
图 10 根据范畴的不同,卡车和公共汽车中的分类与实体类型 Cargo 和 Person发生关系
|
目前,ER 建模中使用了数种表示法,包括陈氏 ER、Barker ER Information Engineering (IE)和 IDEF1X,其中大部分还包含关系表示法。
对象角色建模(ORM)表示法也是 ER 方法学的一员。它能表达非常精确和完整的业务规则,并且可以用图形阐述约束条件。不幸的是,这种详细程度需要具有丰富细节的大量图表。与 ORM 相关的问题是我们是否需要 ER 模型级的表示法精确度。ORM 表示法还很复杂,并且与其他表示法完全不同,因而那些没有使用 ORM 的项目组成员很难理解它。
UML 是一种表示法语言,最初用于软件设计,目前软件设计已经扩展到业务和数据库设计。UML 包括从分析到实施再到部署指定任何事项所必需的元素和图表。通过使用几种图表和数十种元素,UML 还能表达不同程度的系统抽象。这是一项非常独特的功能。但是,我们不需要知道 UML 的所有细节或者成功利用 UML 进行 ER 建模所需的所有视图和表示。
为了更好理解 UML 在 ER 方法学中扮演的角色,我们将描述 UML 如何处理前面已经提到过的 ER 建模的核心元素。
如前所述,实体类型标识了具有同样结构的一系列工件。实体类型是一幅蓝图,根据它能生成只能通过身份和状态互相区别的任意数目的工件。
UML 中的相应元素是类。根据定义,类能够隐藏内容,而实体具有可访问接口。这看上去互相矛盾,但是实际上并非如此。UML 允许类利用公共属性使结构公共化。
类一般用矩形表示,该矩形最多可分为三个部分:
第一部分包括类的原型和名称。原型指的是 UML 中为了强化共同特征而进一步进行的元素分类。比如,所有可能带有遗留原型的遗留类,可能将立即将遗留原型划分为不可修改的一类。虽然类本身是类型的一种表示,但是我们用原型<<实体>>来划分类型(<<…>>是用于指定原型的语法)。
第二部分包含具有类型和可见性的属性。它还可以包含属性的其他细节,比如初始值和原型。第二部分在缩略图中可以省略。
第三部分是为类的行为保留的。由于实体类型不需要行为,所以我们就略过该部分。
根据抽象级别的不同,类可以用一个、两个或三个部分显式。
实体是实体类型的一个实例。在 UML 中,对象是类的实例。这意味着实体本身与对象相对应。
对象的表示来源于类的表示。最显著的区别在于对象的名称有下划线,并且只有一个或两个部分。
第一个部分包含以冒号隔开的可选的原型、对象名称,以及派生类的名称,之间用冒号隔开。至少必须指定其中一个名称。第二部分包含相关属性以及它们的值。
表示对象的最好的方法就是只使用一个部分,并将标识符 指定为对象的名称。
图 11 实体类型 Employees 和实体 553-32-2222 在 UML 中被显示为类和对象
实体的相关状态和信息被作为对象的属性存放。实体类型的属性对于其他实体类型必须是可见的或者公开的。在类规格说明书中属性是按照可见性、名称和类型指定的。属性的类型为分析类型。它在设计阶段可能发生变更。
属性是在类的第二部分指定的。它们包含对于实体总是"+"(公开)的可见性规格说明书。名称与类型之间用冒号隔开。
图 12 具有公开属性(社会安全号码、姓名、地址、出生日期、加入日期和职位)的实体类型 Employees
在 UML 中类之间的关系是为类型而非实例指定的。关系双方上的数字指定了基数:参与该关系的可能实例的数量。
关系的名称是直接在关系行中指定的,用于标识该关系。它有助于读者理解存在这种关系的原因。如果没有为一个关系指定名称,那么角色名将用于帮助读者理解该关系。下图可以这样理解:Products 被 Employees 拥有或者 Employees 是 Products 的拥有者。该关系描述中单词的单复数通过基数确定。
图 13 实体类型 Employee 和 Product 之间的关系
实体类型中用到的数据类型没有被标准化。用户可以使用所需要的任何数据类型。创建具有所有数据类型的术语表是一个不错的做法,因为它可以在公司内多个设计者和项目中实现标准化和可理解性。
关系可以具有属性,这些属性显示在 UML 关联类中。关联类显示在一个矩形中,并且包含该关系的公共属性清单。关联类利用虚线与关系连接。不需要原型来解释类用法和为该类分类,因为附件已经对它做了定义。
关联类中的属性是用可见性、名称和类型指定的。
尽管看上去关联类、附件和关系是独立元素,但是它们实际上代表了同样的元素。关系和关联类的名称必须相关。
图 14 关联类中指定了关系类型 Services 的属性
基数
UML 定义了一种一致的方法来指定基数。它总是被关系双方上的数字指定。可能的定义包括用于一定数量(也可能是不限量的)实例的指定基数的单个数字,以及一对规定了基数的范围的以".."隔开的数字。用于无限基数的符号是"*",它可以单独使用标识可选的无限关系,也可以与另一个很低的值结合使用,来指定强制关系(如"1..*")。基数的下限和上限值可以是任意正数或者"*",但是第一个数字必须小于或等于第二个数字。
图 15 实体类型 SoccerTeam 定义了与 11 到 18 个球员的实体类型 Player 的 plays 关系
依赖关系
UML 可以分辨两种形式的实体类型间的依赖关系。聚合是需要依赖性实体类型的两个实体类型之间的一种依赖关系。UML 中聚合的语法是在聚合方用空心菱形表示。同一方还有一个值为 1 的强制基数,它可以省略。
图 16 每个结婚证实体类型都依赖于扮演新郎和新娘角色的两个人
当聚合不是对于所有依赖关系都唯一,并且不是所有依赖性实例都必须与同一个实体相关时,就可以使用聚合。当聚合是所有依赖关系的唯一实体时,UML 指定了一种叫做组合的强依赖关系。组合被表示为聚合方上的一个实心菱形。当聚合包含下级实体类型时会使用这种关系。
图 17 实体类型 OrderPositions 完全由组合指定的实体类型 Orders 定义
基数可以与聚合和组合一起使用,以便定义这些关系上的约束条件。
实体类型的相同点和不同点分析是必不可少的一部分。特化降低了风险,并通过从父方那里继承需求从而减少了需求匮乏。泛化简化了系统中实体类型的模型和实现过程。
在 UML 中泛化是在关系的父方用空箭头表示的。泛化不是两个实体类型间的一种关系。它是从特定实体类型到一般实体类型的派生。在泛化关系上不允许有基数。
父实体类型的所有属性和关系被特化后的实体类型继承。到其他实体类型的属性和关系不能从特化实体类型中删除。
图 18 泛化将实体类型 Employees 和 Customers 定义为继承了 Persons 属性的实体类型 Persons
同一实体类型的范畴规定了实体如何根据它们的特征(比如所有员工都缺勤)互相相关。分类的语法使用了在 OCL(对象约束语言)中指定的与该关系连接的约束条件。
约束条件旨在指定动态行为。当约束条件被评估为有效时,这些关系也是有效的。
通常约束条件是互相排斥的,可以利用互斥关系之间的约束条件{xor}为约束条件建模。
图 19 实体类型的分类定义了关系类型的标准--Cargo 对于卡车类型的 Vehicle 很重要;Person 可以利用"公共汽车"类型的 Vehicle 被运输
|
与一般的观点不同,ER 方法学并不仅限于关系数据库的开发。笔者不得不同意在大多数情况下,设计流程的输出会在关系数据库中实现;然而,这并不是它的一个条件。ER 方法学的焦点在于基于工件的设计。它输出的是互相有关系的工件(实体类型),以及澄清了实体类型和关系的约束条件。该输出用于创建具有额外技术相关约束条件的关系模型。
ER 方法学用于工件驱动系统的分析和设计。它可用于概念和逻辑上的建模,但本意并非是为了物理设计。ER 方法学只描述了工件的静态视图,而没有描述系统的动态。
为了创建一个平滑的开发流程,开发团队的所有成员需要"操同一种语言",这一点很重要。这是因为对信息的曲解可能导致延误,造成意想不到的错误,并降低团队成员的总体效率。UML 通过提供一种很容易被系统开发团队所有成员理解的标准化语言消除了这些担忧。
本文介绍了统一建模语言(UML)的基础知识,涵盖了UML的发展历程、核心概念及其在软件开发中的应用。文章重点讲解了几种常用的UML图,包括用例图、类图等,并探讨了UML 2.0版本的新特性。
这是关于统一建模语言、即UML 里采用的基本图的一系列文章的一部分。在我
该文是关于在统一建模语言 2.0或UML中使用的基本图的一系列文章中的一部分。在以前关于

107

被折叠的 条评论
为什么被折叠?



