下载
加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 UML对象建模

UML对象建模.doc

UML对象建模

Gemma常平心
2017-11-11 0人阅读 举报 0 0 暂无简介

简介:本文档为《UML对象建模doc》,可适用于综合领域

UML对象建模对于软件是什么以及程序如何工作面向对象编程语言和设计语言有一个共同的理解。对象模型是UML和面向对象编程语言共享的公共计算模型。尽管编程语言和设计语言是在不同的抽象级别来表示程序的但是我们理解这两种语言的基础都是对象模型所提供的对运行程序的抽象描述。本章在一个简单应用的背景下引出并描述对象模型的本质特征。通过例子介绍UML提供的这些概念的表示法说明如何实现这些概念解释设计语言和编程语言之间的密切联系。对象模型不是一个特定的UML模型而是一种考虑程序结构的一般方式。它由构成面向对象设计和编程活动的基础的概念框架组成。如同它的名字使人想起的那样对象模型的基本性质是计算是发生在对象之内和对象之间的。各个对象负责维护系统数据的一部分并负责实现系统整体功能的某些方面。当程序运行时对象典型地由内存区域表示该内存区域中就包含着该对象存储的数据。对象还支持方法或函数以访问和更新对象所包含的数据。因此对象结合了计算机程序的两个根本方面即数据和处理在其他软件设计方法中这二者是分离的。然而程序要比一组孤立的对象集合描述得更多。各个对象中存储的数据之间的关系必须要记录而且程序的整体行为只有从多个不同对象的交互中才能显现出来。通过允许将对象连接到一起可以支持这些需求。典型地这是通过使一个对象能够拥有对另一个对象的引用或者更具体地讲是知道其他对象的位置来实现的。因而对象模型将一个运行的程序视作是一个对象网络或图(graph)。对象构成该图中的结点连接对象的弧称为链接(link)。每个对象包含程序数据的一个小子集对象网络的结构则表示这些数据之间的关系。对象可以在运行时创建和销毁对象之间的链接也可以改变。因此对象网络的结构或拓扑结构是高度动态的会随着程序的运行而改变。对象之间的链接还可以作为对象交互的通信路径使得对象能够通过互相发送消息(messages)进行交互。消息与函数调用类似:消息典型地是请求接收对象执行它的一个方法而且可以附有用参数表示的消息的数据。通常对象对一个消息的响应是向其它对象发送消息这样计算通过网络而展开这个网络将包含响应一个初始消息而涉及到的多个对象。描述一个运行程序的对象的图结构并跟踪各个消息的结果是有可能的:适合做这件事的工具是调试程序。但是通过定义各个对象来编写程序通常是不可行的而是要给出同一类的对象的类(class)的结构描述来定义对象能够持有的数据和方法的执行结果。因此面向对象程序的源代码不是直接描述对象的图而是描述组成这个图的这些对象的特性。在设计中对象模型的重要性在于它为UML的设计表示法提供了语义基础。UML中许多特征的含义可以通过将它们解释为对相互连接的、互通消息的对象的集合的说明来理解。可以绘制UML图(diagrams)来表示对象特定运行时的配置。然而更加常见的是绘制和源代码作用相同的图从一般结构上来定义运行时会发生什么。这些图分成两大类。静态图描述对象之间可能存在的关系的种类以及作为结果的对象网络可以具有的可能的拓扑结构。动态图描述可以在对象之间传递的消息以及该消息对接收消息的对象的影响。对象模型的这种双重作用使得将UML设计表示法与实际的程序相关起来非常容易这也解释了为什么UML是适合于设计和文档化面向对象程序的语言。本章的其余部分将通过用一些基本的UML表示法文档化一个简单程序的例子予以说明。在制造业环境中某些类别的复杂产品是由组成零件装配而成常见的需求是记录所拥有的零件的库存以及这些零件的使用方式。本章我们将开发一个简单的程序来模拟不同种类的零件和它们的特性以及用这些零件构造复杂组件的方式通过这个例子来阐明对象模型。这个程序必须管理描述系统所知的不同零件的信息。除了维护所使用的零件的不同类型信息我们还设想对系统来说记录各个实际零件的信息也很重要可能是为了质量保证和跟踪。对这个例子来说我们假定对每个零件我们感兴趣的是下列三项信息:零件的目录查找号(整数)零件的名字(字符串)单个零件的价格(浮点数值)零件可以被装配成更复杂的结构称为组件。一个组件可以包含多个零件而且可以具有层次结构也就是说一个组件可以由许多子组件构成每个子组件又由零件或可能它自己的更深一层的子组件构成。维护零件、组件及它们的结构信息的程序应该能够用于许多目的例如维护目录和库存信息记录制造的组件的结构支持对组件的各种操作例如计算组件中零件的总价格或者打印组件的所有零件的清单。本章我们将考虑一个简单的应用即通过累加组件中包含的所有零件的价格查出一个组件中的材料价格的查询功能。面向对象系统中的数据和功能分布在系统运行时存在的对象之中。每个单独的对象维护部分系统数据并提供一组允许系统中的其他对象对这些数据进行某些操作的方法。面向对象设计的难题之一就是如何将系统的数据划分到一组对象中这些对象将成功地交互以支持所要求的总体功能。识别对象经常应用的一个经验规则是:用模型中的对象表示来自应用领域的现实世界中的对象。库存控制系统的主要任务之一是记住厂商库存中的所有物理零件。因此很自然的起点就是考虑将这些零件中的每一个都表示为系统中的一个对象。一般会有许多零件对象每个对象描述一个不同的零件因而保存了不同的数据但是每个对象都具有相同的结构。表示同一种实体的一组对象的共有结构由类来描述该类的每个对象称为是该类的一个实例(instance)。那么作为库存管理系统设计的第一步我们可以考虑定义一个“零件”类。一旦确定了候选类我们可以考虑该类的实例中应该放些什么数据。在零件类的情况中一个自然的想法是每个对象应该保存系统必须保存的关于该零件的信息:它的名字、编号以及价格。这反映在下面的实现中。UML类的概念与C和Java这样的程序设计语言中的概念非常类似。一个UML类定义了许多特征(feature):细分为属性(attribute)和操作(operation)属性定义类的实例存储的数据操作定义类的实例的行为。一般地说属性相当于Java类中的域操作则相当于方法。在UML中类由一个分为三栏的矩形图标表示分别包含该类的名字、属性和操作。‘Part’类的UML表示如图图“零件”类的UML表示类图标最上面的部分包含类的名字第二部分包含类的属性第三部分是类的操作。在操作的特征标记(signature)中可以使用程序语言中的类型用冒号把属性名、参数名或操作名与类型隔开。UML也表示了类的各种特征的访问级别用减号表示‘private(私有)’加号表示‘public(公有)’。构造函数下面有下划线以便和类的一般的实例方法相区分。第章将给出UML语法的详尽细节但是在这里值得注意的是图所示的许多细节都是可选的。其中包含类名字的一栏是必需的:在特定的图中如果没有要求可以省略其他信息。类是在编译时定义的而对象是在运行时作为类的实例创建的。执行下列语句的结果是创建一个新对象。它包括两个步骤:首先为对象分配一块内存区域然后适当地初始化。一旦创建了新对象将在变量myScrew中保存它的一个引用。UML定义了描述单个对象及其所保存的数据的图形化表示法。上面一行代码创建的对象可以用UML表示如图所示。一个Part对象对象由分为两栏的矩形表示。上面一栏包含对象的名字及其类的名字都加有下划线。对象不一定要命名但如果有和对象相关的变量用变量的名字为对象命名有时会有用。当要知道对象的类时对象的类名总要说明。通常的风格习惯是类的名字以大写字母开头而对象的名字以小写字母开头。数据作为属性的值保存在对象中。对象图标中下面的一栏包含有对象属性的名字和当前值。这一栏是可选的如果在一个图中不必要显示对象的值时可以省略。对象通常的特性描述表明对象是具有状态、行为和本体的某个东西。下面将更详细地解释这个概念以及相关的封装的概念另外还讲述了实现这些特征的类定义的各种术语。对象的第一个重要特征是它们充当数据的容器。在图中对象的这个特性通过在表示对象的图标中包含数据来描绘。在纯面向对象系统中系统维护的所有数据都保存在对象中:不存在其他模型中的全局数据或中央数据存储库的概念。包含在对象属性中的数据值通常称为对象的状态(state)。例如图中所示的三个属性值构成了对象“myScrew”的状态。由于这些数据值会随着系统的变化而改变结果当然是对象的状态也可以改变。在面向对象的程序设计语言中对象的状态由对象的类中所定义的域指定而在UML中由类的属性指定例如图所示的三个属性值。每个对象除了保存数据之外还提供了一个由若干操作组成的接口。通常其中的一些操作将提供访问和更新对象中所保存的数据的功能但其他操作将更通用并实现系统全局功能的某些方面。在编程语言中对象的操作在它的类中作为一组方法来定义。对象定义的一组方法定义了该对象的接口(interface)。例如节中定义的零件类的接口包括一个构造函数和一些访问函数以返回对象的域中所保存的数据。在UML中操作不同于属性操作没有出现在对象图标中。这是因为对象提供的完全是它的类所定义的操作。由于一个类可以有许多实例每个都提供同样的操作因此显示每个对象的操作会很多余。在这方面对象的行为不同于它的属性因为通常同一个类的不同实例将保存不同的数据因而具有不同的状态。对象定义的第三个方面是每个对象和其他所有对象都是可区别的即使两个对象保存完全相同的数据并在接口中提供完全相同的操作集合时也是如此。例如下面几行代码创建两个状态相同的对象但它们还是不同的对象。对象模型假定为每个对象提供了一个唯一的本体(identity)作为区别于其他对象的标志。对象的本体是对象模型固有的一部分不同于对象中存储的任何其他数据项。设计人员不需要定义一个特殊的数据来区分一个类的各个实例。但是有时应用领域会包含对每个对象都不相同的真实的数据项例如各种识别号码这些数据项通常作为属性建模。然而在没有这样的数据项的情况下也没有必要只是为了区分对象而引入一个这样的数据项。在面向对象的程序设计语言中对象的本体一般由它在内存中的地址表示。由于不可能在同一个位置保存两个对象所有对象都保证具有唯一的地址因而任意两个对象的本体都是不同的。UML允许为对象命名对象名字不同于其所属类的名字。这些名字是模型内部的允许在一个模型中的其他地方引用这个对象。这些名字不对应对象中存储的任何数据项不过可以将名字看作是为对象的本体提供了一个方便的别名。对象的名字不同于刚好保存该对象的引用的变量名。在举例说明对象时如在图中使用保存对象引用的变量名字作为对象的名字通常比较方便。但是可以有多个变量保存对同一个对象的引用并且一个变量在不同的时候可以引用不同的对象所以这种惯例如果随意应用可能很容易引起混淆。对象一般理解为封装(encapsulate)了它们的数据。这意味着对象内保存的数据只能够通过属于该对象的操作来操纵因而一个对象的操作不能直接访问在不同的对象中存储的数据。在许多面向对象语言中通过语言的访问控制机制来提供一种封装形式。例如在节中的零件类的数据成员被声明为‘private’意思是它们只能被同类对象的操作访问。注意这种基于类的封装形式比基于对象形式的封装要弱后者不允许对象访问任何其他对象的数据即使是属于同一个类的对象的数据。尽管节中采用的对零件建模的简单直接的方法很有吸引力但是在真正的系统中不可能令人满意。它的主要缺点是描述给定类型零件的数据是重复的:数据保存在零件对象中而且如果有两个或多个同类型的零件该数据会在每个相关对象中重复。这样至少存在着三个重大问题。首先它含有高度的冗余。系统可能记录一个特定类型的数千个零件它们共有相同的查找号、描述和价格。如果在每个零件中都保存这些数据将不必要地耗尽相当大量的存储。其次价格数据的重复尤其可能会导致维护问题。如果一个零件的价格改变了每个受到影响的对象中的价格属性都需要更新。这样不仅低效而且也难以保证在这种情况下每个相关对象都会被更新并且不会错误地修改了表示不同种类零件的对象。第三需要永久保存零件的目录信息。但是在某些情况下一个特定类型的零件对象可能不存在例如假如零件还没有制造就是如此。倘若这样就没有地方保存目录信息。然而不可能容许只有在相关零件存在时才能保存目录信息。设计这个应用的一个更好的方法应该是将描述给定类型零件的共享信息保存在另外的对象中。这些“描述符”对象并不表示单独的零件而是表示与描述一类零件的目录条目(catalogueentry)相关的信息。图非正式地举例说明了这种情况。这个新设计要求对于系统所知的每种不同类型的零件都应该存在一个单一的目录条目对象以保存该类型零件的名字(name)、查找号(number)和价格(cost)。零件对象不再保存任何数据。为了查找一个零件必需访问描述该零件的目录条目对象。这种方法解决了上列问题。数据只存储在一处因而没有冗余。修改给定类型零件的数据很直接:如果一种零件的价格改变了只需要更新一个属性即相应的目录条目对象中的价格属性。最后没有理由说为什么一个目录条目对象即使没有零件对象与之相关联时不能存在因而解决了在创建任何零件之前如何能够保存零件信息的问题。现在库存控制程序的设计包括了两个不同的类的对象。目录条目对象保存适用于给定类型的所有零件的信息而每个零件对象则表示一个单个的实际零件。目录条目描述的零件然而这些类之间存在一个重要的关系:为了获得对一个零件的完整描述必需查看的不仅是零件对象还要查看相关的描述零件的目录条目对象。实际上这意味着对每个零件对象系统必须记录哪个目录条目对象在描述它。实现这种关系一般方法是如下所示每个对象包含一个到相关目录条目的引用。目录条目类现在包含着描述零件的数据零件是用一个目录条目进行初始化并且保存对该目录条目的一个引用。在创建一个零件时必须提供适当的目录条目对象的一个引用。这样做的根本原因是:创建一个未知的或未指定类型的零件是没有意义的。下面的代码显示了如何用这些类创建零件对象。首先必须创建一个目录条目对象而后可以用它初始化所需的任意多个零件对象。如同在节中解释的那样一个类的域在UML中通常是作为类的属性来建模。然而如果一个域包含着对另一个对象的引用例如上面的Part类中的entry域这种方法就不合适。属性定义的是保存在对象内部的数据但目录条目对象并不是保存在零件内部而是单独的对象能够独立于任何零件对象存在并能够同时被多个零件对象引用。在UML中一个对象保存另一个对象的引用的事实通过在这两个对象之间画一个链接(link)来表示。链接表示为一个箭头从保存引用的对象指向被引用的对象而且在链接的箭头上可以标示保存引用的域的名字。因此上面的代码所创建的对象可以用UML建模如图所示。对象之间的链接链接上的箭头表示只能在一个方向上遍历或导航。这意味着零件对象知道它所链接的目录条目对象的位置并有权访问目录条目对象的公有接口。这并不隐含着目录条目对象对引用它的零件对象具有任何访问权限它甚至不知道该零件对象。在另一个方向的访问只能通过在目录条目中保存对零件的引用来提供从而使链接在两个方向都是可导航的。对象图(objectdiagram)是表示对象和对象之间的链接的图形表示。图是一个很简单的对象图的例子。对象图是以可见的形式表示节所讨论的对象的图结构的一种方式:它们给出了系统中的数据在给定时刻的一个“快照”。在链接着的对象的结构中信息是用两种不同的方法记录的。一些数据明确地作为属性保存在对象中而另一些信息纯粹是在结构上依靠链接保存的。例如零件属于给定类型的事实是通过零件对象和相应的目录条目之间的链接表示的:在系统中没有明确地记录零件的类型的数据项。正如同用类定义一组相似对象的共同结构一样这些对象之间的链接的共同特性也可以通过相应的类之间的关系定义。在UML中类之间的数据关系称为关联(association)。因而链接是关联的实例就如同对象是类的实例一样。在库存控制的例子中图中的链接必须是零件类和目录条目类之间的一个关联的实例。在UML中用一条连接相关的类的线来表示关联与上面的链接相对应的关联如图所示。注意为了清晰起见图中没有显示目录条目类的所有已知信息。两个类之间的关联这个关联用UML建立了一个模型它定义了在Part类中的entry域。因为entry域保存了一个引用所以关联表示为只在一个方向上可导航。类似于相应的链接在关联的一端标记着域的名字。以这种方式放置在关联端点的标记称为角色名(rolename):它的位置反映了“entry”这个名字在零件类中用来引用所链接的目录条目对象的事实。在关联的端点还标明了一个重数约束(multiplicityconstraint)这个例子中是数字“”。重数约束表明一个给定的对象在任一时间能够和多少个实例链接。在这个例子中约束是每个零件对象必须链接到恰好一个目录条目对象。但是这个图没有规定多少个零件对象可以链接到一个目录条目对象。重数约束给出了关于模型的很有价值的信息但同样重要的是要知道它没有表达出来的东西。例如对库存控制系统的一个合理的特性需求是:一个零件应该总是链接到同一个目录条目对象因为建模的实际零件不能从一种类型变成另一类型。然而这里显示的重数约束并没有强制这点:在任何给定时间应该只有一个链接的目录条目这个约束并未含有在任何时候都是相同的目录条目的意思。值得注意的是上面给出的Java的Part类实际上没有实现图所示的重数。因为在Java中是引用域的合法值所以如果将作为零件类的构造函数的参数那么有未链接到任何目录条目的零件对象是可能的。这与一个零件应该总是链接到恰好一个目录条目对象的重数约束相矛盾。Part类的一种更健壮的实现可以是在运行时对此进行检查在试图用一个引用初始化时抛出一个异常。正如对象图显示对象和链接的集合一样类图(classdiagrams)包含了类和关联。图是一个简单的类图的例子。尽管对象图显示系统的对象的图的许多特定的状态而类图则以一种更一般的方式指定了系统的任何合法状态都必须满足的特性。例如如果图表示在任何给定时间库存控制系统的对象图能够包含“Part”和“CatalogueEntry”类的实例并且每个零件对象必须链接到恰好一个目录条目。那么假如程序进入了一种状态譬如说存在连接两个目录条目的链接或者零件没有链接到目录条目就会出现一个错误而程序则处于一种非法状态。按照术语固有的外延如果对象图满足类图中定义的各种约束那么称对象图是类图的实例。本章早先的例子已经说明在面向对象的程序中数据是如何在系统中跨对象分布的。尽管一些数据作为属性值明确地保存但是对象之间的链接也含有信息它描述了对象之间持有的关系。信息的分布意味着为了完成任何有意义的功能一般地许多对象需要进行交互。例如假设我们想要为零件类增加一个方法使得我们能够检索单独一个零件的价格。但是表示零件价格的数据值并没有保存在零件对象中而是保存在零件引用的目录条目对象中。这意味着为了检索该数据这个新方法必须调用目录条目类中的getCost方法如下面的实现所示。现在如果客户持有一个零件的引用并需要找到它的价格可以如下简单地调用cost方法。UML将方法调用表示为从一个对象发送到另一对象的消息。当一个对象调用另一对象的方法时可以看作是请求被调用的对象执行某些处理这个请求作为一个消息建模。图显示了对应于上面的代码中调用scost()的消息。发送一个消息图中的client对象只有对象名字而没有类名字。“cost”可以由多个不同类的对象发送给一个零件而消息发送者的类与理解消息以及零件对象对消息的响应无关。因此在像图这样说明特定的交互的对象图中省略客户类比较方便。客户代码持有对零件对象的一个引用保存在变量s中如前所述这在图中表示为一个链接。这个引用还使得客户能够调用链接的对象的方法然而这意味着在UML中对象之间的链接也表示了消息的通信信道。在对象图中消息用链接旁边带标记的箭头表示。在图中显示了一个客户对象向零件对象发送消息请求得到零件的价格。消息本身则用常见的“函数调用”符号书写。对象在接收到一个消息时通常会以某种方式响应。在图中预期的响应是零件对象向客户对象返回自己的价格。但是为了查找价格零件对象必须调用它所链接的目录条目对象中的getCost方法。这可以用第二个消息表示如图所示。查找零件的价格图还举例说明了表示消息返回值的UML表示法。返回值写在消息名字的前面并用赋值符号“:=”分隔开。在不显示返回值时或者没有返回值时如图所示可以简单地省略这个符号。以上所示消息的语义是普通程序函数调用的语义。当一个对象给另一个对象发送消息时程序中的控制流从发送者传递给接收消息的对象发送消息的对象一直等到控制返回时才继续自己的处理。除了维护单个零件的详细资料之外库存控制程序还必须能够记录这些零件如何装配成组件。图所示的是一个包含一个strut(支杆)和两个screw(螺旋)的简单组件。注意在这个图中省略了目录条目类中的无关属性。一个简单组件在图中有关组件(Assembly)中包含哪些零件(Part)的信息是通过连接组件和零件对象的链接表示的。这些链接不是用角色名标示而是用关联名标示。关联名描述链接的对象之间具有的关系。关联名通常是经过选择的像这里一样使得可以从关联名以及所链接的类名构造出描述这种关系的语句。在这个例子中合适的语句可以是“一个组件包含(contains)零件”。组件类的实现必须提供一种方法能保存对不定个数零件的引用。一种简单的支持方法是在类中包含一个数据结构该数据结构能够保存该组件对所有零件的引用如下所示。图中的链接实例所属的关联在图中表示了出来。如链接那样关联上标明了关联名写在关联的中间。关联端点的“*”符号是一个重数注文含意是“个或多个”。在这个图中它指定一个组件可以链接或包含零个或多个零件。组件和零件之间的关联图中的图在关联端点标示的角色名‘parts’对应于Assembly类中用于保存引用的域从而文档化了上面代码中关联的实现。通常为了让图的含意更清晰可以使用所需要的任何名字和角色名的结合来标明关联和链接。然而将一个组件简单地作为一组零件建模是不够的。组件可以有层次结构零件能够装配为子组件子组件可以和其他子组件与零件装配在一起形成更高层次的组件可以达到任何需要的复杂度。图显示了一个简单的例子它在图所示的结构中引入了一个子组件。层次组件为了实现层次结构组件必须能够包含零件和其他组件。这意味着和图不同中标示有‘Contains’的链接全都是把一个组件对象连接到一个零件对象而在图中标示着‘Contains’的链接还可以把一个组件对象连接到另一个组件。如同许多程序设计语言一样UML也是强类型的语言。链接是关联的实例因而由链接连接的对象必须是相应的关联端点的类的实例。在图中这个要求是满足的:如图规定的那样每个标示有‘Contains’的链接连接该组件类的一个实例到该零件类的一个实例。但是图中违反了这个条件因为‘Contains’链接将顶层组件实例不是连接到一个零件对象而是连接到了一个组件类的对象。如果我们想要建立层次组件的模型在这些链接的“被包含的”一端必须不能像图所指定的那样约束为只是‘Part’类而是或‘Part’类或‘Assembly’类。这是一个多态性(polymorphism)的例子:多态性的意思是“许多形态”暗示在某些情况下通过同一类型的链接需要连接多个类的对象。UML是强类型的所以不允许链接连接任意类的对象。对于如图所示的多态链接必需指定能够参与链接的类的范围通常的实现方法是定义一个更一般的类并说明我们希望链接的特殊类是这个一般类的特化。在库存控制程序中我们想要建立模型是在此模型中组件能由构件(component)组成而每个构件可以是一个子组件或是一个零件。这样就能够规定‘Contains’链接把组件对象连接到构件对象而按照定义构件对象或是零件对象或是表示子组件的其他组件对象。在面向对象语言中是使用继承(inheritance)机制来实现多态性。可以定义一个构件类而将零件类和组件类定义为构件类的子类如下所示。和Assembly类较早的实现不同那里定义了将一个零件加入到组件中的方法这里相应的方法是将一个构件加入到组件中。然而在运行时实际创建并加入到组件的对象将是零件类和组件类的实例而不是构件类自身的实例。Java中继承语义的含义是可以在任何指定超类引用的地方使用子类的引用。在这里这意味着零件和组件的引用都可以作为add函数的参数来传递因为这些类都是构件类的子类而函数的参数指定为构件类。组件类的实现可能甚至比这更具多态性因为其中使用了Java库的“Vector”类来存储对构件的引用而Vector类可以保存任何类型对象的引用。对构件类的限制是由“add”方法的参数类型强加的它提供了客户向组件中加入构件的唯一方法。UML这个例子中多态性的实现由两种不同机制相互作用而产生。第一定义组件类使得它能够保存对多个构件对象的引用第二用继承定义子类表示存在的不同类型的构件。于是程序设计语言规则就导致一个组件能够保存对不同类型构件的混合引用。Java的‘extends’关系在UML中用类之间的特化(specialization)关系表示:如果类E是通过扩展类C而定义的那么就说E是C的特化。如果从超类比子类有更大的范围的关系的角度看这种关系也被称为泛化(generalization):等价的描述可以说C是E的泛化。泛化或者特化在UML类图中用一个将该关系中的子类连接到超类的箭头描绘。这些关系与关联在直观上的区别是箭头的形状。图显示了库存控制例子中的类之间的特化关系。构件之间的泛化关系和关联不同泛化没有在对象图中出现的“实例”。尽管关联描述的是对象能够链接到一起的方式泛化描述的则是一个类的对象能被另一类的对象替换的情形。正因为这样重数的概念不适用于泛化并且一般也不标注泛化关系。最后考虑到图中的泛化我们可以重新定义图中的关联。结果情况如图所示该图还文档化了上面给出的Component、Part和Assembly类的实现。允许层次组件的模型图表明组件能够包含零个或多个构件(关联)每个构件可以是一个零件或是一个组件(特化)。在后一种情况下我们有了一个组件包含在另一个组件之中的情形因此这个类图允许构造如图所示的层次对象结构。与零件和组件类不同我们决不会期望创建构件类的实例。零件和组件对应于应用领域中的真实对象或结构但是构件类是一个概念的表示即零件和组件可以认为是更一般的构件概念的特例。在模型中引入构件类的原因不是为了能够创建构件对象而是为了指定零件和组件在某些情况下是可互换的。像‘Component’这样的类其引入主要是为了指定模型中其他类之间的关系而不是为了支持新类型对象的创建这样的类称为抽象类(abstractclasses)。如上面举例说明的Java允许将类声明为抽象的而在UML中可以通过将类名字写成斜体表示如图和所示。如果传递给组件对象一个消息请求得到它的价格那么组件对象满足这个请求的方法是向自己的构件请求得到它们的价格然后返回所得到的价格的总和。自身也是组件的构件对象将向自己的构件发送类似的‘cost’消息但是若构件是简单零件时就向它所链接的目录条目对象发送‘getCost’消息如图所示。层次中的消息传递如果组件对象处于图中的层次的顶端时向它发送一个‘cost’消息后将会产生的所有消息在图中给出。注意在面向对象程序中单个请求非常容易引起系统中对象之间的一个复杂的交互网。在这个交互中组件对象通过向自己的所有构件发送同样的消息来计算出价格即‘cost’。发送消息的对象不知道特定的构件是一个零件还是一个组件实际上也不需要知道。它只是简单地发送消息并依赖接收对象以一种恰当的方式解释这个消息。当接收到一个‘cost’消息时实际进行的处理将依赖于消息是发送给了组件对象还是零件对象。这种行为称为动态绑定(dynamicbinding)或晚绑定(latebinding):实质上是消息的接收者而不是发送者来决定执行什么代码作为所发送消息的结果。在多态的情况下消息接收者的类型可能直到运行时才可以知道因而响应消息所执行的代码只能在运行时选择。在Java中获得这种行为很简单通过在构件类中声明cost函数然后在零件类和组件类中重定义cost函数为各个类提供需要的功能如下面所示的来自相关类的摘录。其他语言提供晚绑定有不同的方法:例如在C中就必须使用虚函数机制。本章已经讨论了对象模型的基本特征并着重讨论了对象模型的概念与面向对象编程语言的概念之间的联系。但是对象模型在软件开发生命周期从需求分析开始的所有阶段都要使用因而研究对象模型对这些活动的适用性也很重要。通常说面向对象的观点是受到了我们平常看待世界的方式的启示。事实上我们的确是把世界作为是由对象组成来感知和认识的这些对象具有各种特性、互相交互、以各种独特的方式行动而对象模型则认为是这种一般意义上观点的反映。因此有时甚至进一步声称对象建模非常容易软件系统中需要的对象可以简单地通过研究所建模的现实世界领域而发现。在某些系统中情况的确是这样其中一些被建模的现实世界对象和一些软件对象之间存在着相当直接的对应但是这不能类推而作为建立面向对象系统的一种非常有用的指导。设计软件的首要目标是产生满足用户需求的、易于维护的、易于修改和复用并且能够有效利用资源的系统。但是一般而言认为简单地复制所感知的现实世界中的对象就能产生具有这些良好特性的软件是不合理的。例如将零件直接表示为节的零件对象节表明这样会导致重大的效率问题和可维护性问题至于它能否满足系统的功能需求甚至也存在疑问。由于过分强调现实世界对象的特性而导致的拙劣设计的另一个典型例子将在节中给出。此外在对象模型中用于对象之间通信的消息传递机制似乎也没有准确地表现现实世界中许多事件发生的方式。例如考虑这样一种情形两个人没有注意走到某个地方互相偶然相遇。将这种情形想象为是其中一人向另一人发送了一个“相遇”消息是与直观相违背的。两个人是平等的而且无意识地参与了一个事件的发生这样似乎更恰当一些。由于这样的原因一些面向对象的分析方法建议根据对象和事件建立现实世界的模型而只在设计过程的后期才引入相关的消息。无疑地存在一些案例其中现实世界的对象特别是代理可以认为是给其他对象发送消息。然而对象模型最有意义的长处不是来自它对现实世界建模的适宜性而是来自具有面向对象结构的程序和软件系统更可能拥有许多人们想要的特性的事实例如易于理解和维护。理解面向对象最有益的是作为一种特别的方法解决如何将软件系统中的数据和处理相关在一起。所有的软件系统都必须处理一组给定的数据并提供操纵和处理这些数据的能力。在传统的过程式系统中数据和处理数据的函数是分离的。系统的数据认为是存储在一个地方而应用需要的功能则通过一些操作提供这些操作能自由访问任何部分的数据同时在本质上保持与数据的分离。每个操作都有从中央存储库中选取自己感兴趣的一部分数据的责任。可以立即得出对这种结构的一种看法是大多数操作将仅仅使用系统整个数据的一小部分并且大多的数据块将只是由少数操作访问。面向对象方法试图做的是将数据存储库划分为许多独立的数据块并将数据块和直接操纵该数据块的操作集成在一起。这种方法与更传统的结构相比能够提供许多重要的技术优势。然而用容易理解的话来说面向对象设计的益处似乎不是来自对象模型特别忠实于现实世界的结构而是来自这些操作与它们所影响的数据都局部化在一起而不是作为庞大而复杂的全局结构的一部分。面向对象建模语言是建立在抽象的对象模型的基础之上的对象模型将运行的系统看作是一个交互的对象的动态网络。该模型还提供了对面向对象程序运行时特性的一个抽象解释。对象包含数据和一组操纵该数据的操作。每个对象和其他对象都是可区分的不论其保存的数据或提供的操作相同与否。对象的这些特征称为对象的状态、行为和本体。类描述了一组共享相同结构和特征的对象这些对象称为是这个类的实例。对象一般阻止外部对象访问自己的数据称为封装。对象图显示运行时的一组对象以及对象之间的链接。对象可以被命名并且可以显示它们的属性值。对象通过发送消息和其他对象合作。当对象收到一个消息时它执行自己的一个操作。向不同的对象发送相同的消息可以引起执行不同的操作。对象之间以消息形式进行的交互包括参数和返回值可以在对象图中表示。类图提供了对一组对象图中所显示的信息的一个抽象总结。它们显示与一般在系统源代码中找到的相同的信息。在面向对象建模中经常使用的一种经验规则是以现实世界中发现的对象作为设计的基础。但是以这种方式得到的设计的适宜性需要谨慎地评价。画出一个完整的类图描述本章讲述的库存控制程序的最后的情况包括在节选的代码中定义的所有属性和操作。假设执行了下面一段代码:(a)画图说明已经创建的对象、它们的数据成员以及它们之间的链接。(b)下面的代码创建一个组件对象并向其加入了上面创建的一些对象:画图说明这段代码执行之后组件a中包含的对象以及它们之间的链接。(c)下面代码的执行可以说明向组件a发送了一个cost()消息。将执行这个函数期间会在对象之间发送的消息加入到你的图中。图Ex中的对象图描绘了库存控制系统的不可能状态根据图和中的类图解释这是为什么。Ex库存控制程序的非法状态用一个图举例说明下列UML的对象、链接和消息表示法的使用。(a)类Window的一个对象不显示属性。(b)类Rectangle的一个对象以及属性length和width。假设矩形类支持一个返回矩形对象的面积的操作。(c)Window对象和Rectangle对象之间的一个链接模拟矩形定义了窗口的屏幕坐标的事实。(d)Window对象向Rectangle对象发送一个消息请求得到它的面积。画出一个类图显示具有本习题中提到的特性的Window和Rectangle类。假定一个环境监测台装有三个传感器即温度计、雨量计和湿度计。另外还有一个输出设备称为打印机显示这三个传感器的读数。每分钟取一次读数并转录到打印机。这个过程称为“获取检查点”。(a)绘制一个对象图表明这些对象可能的配置图中包含在每次获取检查点时系统中可能产生的消息。假设检查点由一个从定时器对象发送到监测台的消息启动。(b)你的图中是否清楚地显示了消息发送的次序?如果没有应该如何表明?(c)画出概括监测台结构的类图。一个工作站当前有三个用户登录帐户分别是A、B和C。这些用户运行了个进程进程的ID分别是、、和。用户A正在运行进程和B在运行C在运行。(a)绘制对象图描述表示工作站、用户和进程的对象以及表示在工作站上运行的进程和拥有进程的用户的关系的链接。(b)考虑有一个操作列出当前运行在工作站上的进程的信息。该操作可以报告所有当前进程的信息或者在用适当的参数调用时报告单个指定用户的进程的信息。讨论为了实现这个操作需要在(a)部分所显示的对象之间传递什么消息。对本章讨论的程序的另一种设计可以是取消零件类和目录条目类而用不同的类来表示每种不同类型的零件。模型中可能包括例如“螺旋”、“支杆”和“螺栓”等类。每种零件的查找号、描述和价格将作为静态数据成员保存在相关的类中单个零件只是这些类的实例。(a)这种改变对程序的存储需求会产生什么影响?(b)为这种新设计设计一个组件类。为了保证组件能够包含不同类型的零件你需要作什么假设?(c)画出这个新设计的类图。(d)随着系统的进化可能必须加入新类型的零件。解释这将如何完成:一是在本章提出的原始设计中二是在本习题考虑的另一种设计中。(e)根据这些考虑你认为这两种设计中哪个更可取是在什么情况下更可取?假设为库存控制系统定义了一个新需求维护库存的并且当前没有在组件中使用的每种零件的数量。确定这些数据应该保存在哪里并在适当的对象图上画出消息显示每当零件加入到组件时数量是如何递减的。组件的“零件剖析”是一个报告它以某种适当的格式完整地列出了组件中的全部零件。扩充库存管理程序以支持打印一个组件的零件剖析。如同图中那样通过一个表示典型组件的包括有消息的对象图来阐明你的设计。在节中提到创建零件对象时没有将其链接到适当的目录条目对象是错误的。但是节中给出的Part类的构造函数并没有强制这个约束因为它没有检查传给它的目录条目引用不是如果是那么将创建一个没有链接到任何目录条目的零件对象。扩充节定义的构造函数以切合实际的方式处理这个问题。

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/37

UML对象建模

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利