面向对象设计方法.doc_第1页
面向对象设计方法.doc_第2页
面向对象设计方法.doc_第3页
面向对象设计方法.doc_第4页
面向对象设计方法.doc_第5页
免费预览已结束,剩余32页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第10章 面向对象的设计方法:用例实现本章目录概述210.1面向对象设计分析和程序设计的桥梁310.1.1面向对象程序设计概述310.1.2面向对象设计过程和模型610.2设计类和设计类图710.2.1设计类图符号810.2.2设计类符号910.2.3一些基本的设计准则1010.2.4开发初步设计类图1310.3交互图实现用例和定义方法1410.3.1 对象职责1510.3.2用例控制器1510.4用顺序图设计1610.4.1初步顺序图1710.4.2顺序图初步设计的规则1910.4.3为“查询可用条目”用例创建一个多层次设计1910.4.4为RMO电话订购建立初步顺序图2310.4.5为电话订购场景创建一个多层次设计2610.5用协作图设计2810.6更新设计类图3010.7包图将主要部分结构化3210.8三层设计的实现问题34小结35关键术语35参考资料36学习目标阅读本章后,你应具备如下能力:解释面向对象设计的目的和目标开发设计类图根据对象职责准则和用例控制器开发交互图开发作为系统设计核心过程的顺序图开发作为系统设计一部分的协作图用包图记录结构设计本章要点面向对象设计分析和程序设计的桥梁设计类和设计类图交互图实现用例和定义方法用顺序图设计用协作图设计更新设计类图包图将主要部分结构化三层设计的实现问题NEW CAPlTAL BANK尽管在项目开始的时候有一些问题,但是现在看来一切都在掌握之中。Bill Santora是New capital Bank的项目经理,负责开发一个集成客户账目系统,他刚刚和审查委员会的委员们完成了对新系统初步设计的技术审查。初步设计关注六个核心用例,它们作为系统最基础的部分,在第一次迭代中完成。New capital Bard(已经使用了一段时间的面向对象语言,但开始使用面向对象分析和设计的技术却比较晚。Bill Santora曾用面向对象的技术开发过一些系统,比如用统一过程(UP)和统一建模语言(UML)开发早期的导航系统。但是,这次的开发项目是他第一次遇到的完全面向对象的大规模项目。Bill Santora把材料给他的上司Mary Garcia,Mary Garcia说:“你的技术评审做的非常好。委员们只提出了很少的需要修改的部分。虽然我不是太明白面向对象技术,但是我还是看懂了你给我的材料和主要的功能。我很难相信你能在下面两个星期完成这六个部分。”Bill santora笑着说:“等等,只完成这六个主要功能的编码和运行并不意味着项目的结束。这个项目还需要一年的时问来完成。”“是的,我知道。但是两个月之后我们可以做出点东西来就很好。不单只有我对项目有信心,用户也愿意看到事情有所进展。”“没错,别忘了我开始提出用UP来做这个项目的时候是多么的艰难!因为UP是一种迭代的方法,所以为以后的迭代制定计划是比较困难的。我花了很长的时问让大家相信这个项目的风险不是很大。因为每次迭代只有六个星期的时间,所以在开始阶段就要展示一些东西。你不知道设计通过评审之后,我的压力就会减轻很多。大家做了很多工作来确保设计的可靠性,我们觉得很有信心。能够得到认可是多么好的一件事。在接下来的两个星期我们还有一些关于新系统的基本工作要做。”“采用渐增式的方法很有意义。我尤其喜欢你给每个用例设计做的详细的顺序图。支持每个用例的三层设计,你做得非常好。我能明白每个用例是怎样完成的,但是我还是不太明白先进的面向对象技术。我想当你证明用同样的基本设计可以既为我们内部银行出纳员又为Web端的用户设计系统时,大家会拍手为你叫好的,祝你成功!”Bill Santorla回应了Mary Garcia的祝贺,说:“类图的设计怎么样?你不觉得类图使得类和方法看上去更加明白吗?我们在组内讨论的时候都是用它们进行交流的,它们确实能帮助程序员写出好的、可靠的代码。”“顺便问一下,你们安排再和用户进行复审了吗?”Mary Garcia问。“没有,我们在开发用例和创建用例描述的时候和用户联系比较紧密。我们还和用户共同开发了所有这些用例的原型。所以,我们无须向用户解释设计模型的细节,就可以对这些用例进行编码了。毕竟,几个星期后我们要给他们展示一些东西。然后,我们和用户有下一轮的会议,让他们给我们的工作提意见,我们便可以开始下一阶段的迭代。我们需要他们的意见来开发下一阶段的用例描述。”“我很期待看见第一阶段的成果。在项目的后续开发过程中可以测试这些核心功能是很有意义的。让我再次祝贺你。”Mary Garcia建议和Bill一起去吃午饭。概述回忆一下第2部分,面向对象分析是由两个目标组成的,即发现和理解。发现是由发现事实的活动组成的,比如和系统用户面谈,而理解是提取从被采访用户那里得到的信息并且构造相互关联的广泛的模型的过程。在第5章,学习了如何识别问题的主要类和用例,这些类和用例提供了理解系统需求的基本信息。在第7章,学习了如何通过细节描述、活动图和系统顺序图(SSD)扩展每一个用例的方法,以及通过继续精炼域模型类图的方法来完成面向对象分析需求模型。建立模型是理解用户需求必不可少的部分,同时也影响着最终的系统。然而,要记住建立分析模型的目的不是描述新的系统,而是更精确地理解系统需求。第9章介绍了结构和详细设计方面的概念。你现在已经知道了系统设计要关注很多系统方面的问题,如网络设计、应用设计、数据库设计、用户界面设计和系统界面设计。本章和下一章的主要问题是如何开发面向对象设计模型,程序员要用这些模型来为系统编码。两个必须开发的最重要的模型是设计类图和交互图(顺序图和协作图)。你将学到如何为三层设计中的每一层开发设计类图,这三层包括域层、可视层和数据访问层。设计类图扩充了分析阶段开发的域模型。交互图也扩展了分析阶段开发的系统顺序图。我们还将讨论如何将类关联到包图中,并说明其中的联系和依赖。最后,我们讨论一些优秀的设计准则,以及应用这些准则的方法。10.1 面向对象设计分析和程序设计的桥梁如果我们把开发新的软件系统比做盖房子的话,我们说分析就像是建筑师最开始的设计草图和方案图。这些草图描绘了房屋的主人对卧室、地板、布局、位置等的想法。然而,仅有这些草图承包人是不知道该如何建造房子的,他需要更详细的信息。所以,建筑师需要利用草图做出更详细的计划,称之为蓝图。蓝图详细规定了墙、地板和天花板的样子,对电线和管道设备,甚至是该用什么样的材料都进行了详细的说明。这些详细的蓝图和软件开发者构建的设计模型是类似地。可以进一步类推,草图设计好之后,屋主可以再提出他们的要求,但是屋主一般不参加细节设计。屋主评估并纠正设计细节,但是墙内线路和管道的设计是专家或是建筑师指导承包人完成的。类似地,在软件设计中,细节设计规范主要是由软件设计专家完成的,用户只是偶尔参与主要是为了对设计进行纠正。所以什么是面向对象设计呢?它是一个建立一系列面向对象设计模型的过程,程序员利用这些模型对系统进行编码和测试。系统设计是用户需求和新系统程序设计之间必不可少的桥梁。建筑者如果没有蓝图,是怎样也不会建造出比狗窝或是小屋大的东西的,同样,系统开发者如果没有设计模型是不会开发出一个大规模的系统的。有的时候,学生在做课程设计的时候需要开发个人的网页或是小型的系统,但是他们认为设计模型不重要。但是要记住,对于建造狗窝来说蓝图可能不重要,但是对于复杂的东西,比如说房屋,蓝图是必不可少的。我们这章讲的应用软件的设计,只是面向对象设计的一部分。正如你在第9章中学到的,用户界面设计、网络设计、控制和安垒设计、数据库设计同样也需要设计任务和设计模型。10.1.1 面向对象程序设计概述要理解面向对象程序设计,我们首先要理解一个面向对象程序是如何工作的。面向对象程序是由一系列协同完成某一任务的程序对象组成。每个程序对象有程序逻辑和一些必要的属性,这些逻辑和属性封装在一个单元中。对象之间通过互相传递消息来协调工作,它们共同工作来完成主程序的功能。图10-1描述了一个面向对象程序是如何工作的。这个程序包括一个输入窗口对象,该窗口用来输入学生ID,以及其他信息。当学生输入ID后,窗口对象会发出消息(消息2)给学生类,程序会产生一个新的学生对象(实例),同时也转到数据库中取得学生信息并把这些信息组成一个对象(消息3)。一旦那样执行了,新的学生对象会给窗口对象返回一个消息并显示在屏幕上。职员此时会输入个人信息的更改(消息4),与此同时,发送了消息的另一个消息序列可用来更新程序中的学生对象和数据库中的学生信息。面向对象程序有个一般性问题,即到底是谁在控制这一切呢?在结构化程序中,哪个模块是主模块,哪个模块控制着计算任务,这都是很明显的。然而在面向对象程序中,这就不明显了。实际上没有哪个模块能进行控制。没错,有一个启动程序,但是一旦程序开始执行,就没有哪个模块或对象来控制了。图10-1 面向对象事件驱动程序流让我们用一个或许是你很熟悉的类比计算机类比来比较一下面向对象程序和结构化程序的不同。主机是一个具有强大计算能力的大型机,一个主机也许连接并控制着几千个独立的终端,终端只有在主机指令下才会工作。主机也能对数据库进行存取,这一点很像结构化程序。相反,许多由网线连接起来的独立的计算机组成了一个个人计算机网络。每个计算机都有计算能力。如果你在一台计算机士工作,你能通过一个信息或产生求助信号联系另一台计算机。例如,网络上一些计算机也许有很大的硬盘和能访问的数据库,我们称它们为文件服务器。其他资源,如网络打印机。如果你在一个网络环境中工作并且需要打印一些东西,你的计算机就会发出一个请求打印的消息给控制打印机的计算机。在许多你所熟悉的网络中,各个独立的计算机没有单独且一致的任务,但可以假设有一个中心任务。每个计算机能完成整个任务的部分功能。计算机共同工作,通过互相之间再次发送消息来完成整个计算任务。这种系统工作与所设计的面向对象的系统或程序很相似。一个面向对象系统由一系列计算对象组成。每个对象都封装了它自身的数据和程序逻辑。分析员通过一个类来定义程序逻辑的结构和数据字段。类定义描述了一个执行对象的结构或模板。只有当程序开始执行时,对象才能存在。这个过程我们称之为类模块的实例化,或基于类定义所提供的模板生成对象实例。 实例化:根据类定义所提供的模板创建对象。 面向对象设计的目标是识别并确定所有对象,并生成每个用例,比如用户界面对象、问题域对象及数据库访问对象。正如第9章所讨论的,由于在逻辑上我们可以把对象分为三层,因此被称为多层设计。除了识别类以外,另一个设计目标是用足够的细节来说明每一个类,使得程序员能理解这些对象是如何协同工作以生成用例的,并可以为每一个类编写面向对象的代码。对于一个学生注册系统,用程序语言实现的部分类的定义可以参考图10-2(a)和10-2(b)。我们先用Java实现了类的定义,然后用Visual Basic.NET实现了类的定义。(a)用Java实现的学生类的定义图10-2 学生注册系统的类的定义(b)用Visual Basic实现的学生类的定义图10-2 (续)作为面向对象系统的设计者,你要为程序员编写初始的类定义提供足够的细节,并可以不断在代码中添加细节。在下面的部分你会看到,面向对象设计的主要部分是设计类图、交互图,还要设计有些类的状态图。比如,一个设计类说明帮助定义了属性和方法。在本章的后半部分你会学到设计类的具体方法,但是作为一个很重要的例子,我们可以先看一下图10-3。你应该可以看出这些属性和方法对应图10-2中的哪部分代码。注意,类名、属性和方法名来源于设计类符号。当然在设计类的时候,我们比较自由地缩减了第一个名字和最后一个名字来简化名字,并且把所有的地址成分组合到一起,称之为地址。如果程序员不知道是否该把这些简化了的名字分开,那么设计者就不能这样进行简化。其他需要被加入到类定义中的代码能够从其他的设计模型中获得,包括交互图和功能图。当我们讨论设计类的时候,要不断回过头来看看图10-2中的代码,可以帮助我们看到设计和编程实现之间的联系。我们还要讨论面向对象设计中的其他模型和图,这些其他模型如包图和部署图,它们对文档设计是很有用的。但是要记住,主要的面向对象设计模型是设计类图和交互图,有些地方还需要状态图。图10-3 Student类的简化设计类10.1.2面向对象设计过程和模型在这一章中,我们关注了三个面向对象设计模型,即设计类图、交互图和包图。图10-4说明了用哪种分析方法来开发哪种设计模型。左边的模型用例图,用例描述和活动图,域模型类图和系统顺序图是在分析阶段开发的。右边的那些模型设计类图,交互图和包图将在设计阶段开发。从图中的箭头可以看出,交互图是设计中的核心图,在这一章中你将学到如何开发交互图。本章你还将学到的主要设计模型是设计类图。它的主要功能是编写文档并描述新系统中要建立的程序类。它们描述了程序设计中一系列需要的面向对象类、类之间的联系、特征名称和属性、方法名称和属性。如图10-4所示,这些信息有两种来源:域模型类图和交互图。事实上,设计类图和交互图之间的箭头有两个方向。双向箭头说明了设计类图中的一些信息要用来完成交互图,而交互图中的一些信息也被用来完成设计类图。设计过程要求一些步骤,包括迭代。首先创建设计类图的基础版本,或是初步模型。初步模型中要包含一些诸如属性名称的基本信息,以便用来设计交互图。图10-4 带有各自输入模型的设计模型设计中的第二个阶段是开发交互图,即为每一个用例产生一个交互图。开发一个交互图需要很多步骤,交互图决定了哪些对象一起工作,以及怎样协同工作。开发交互图是面向对象系统设计的核心。正如图10-4所示,交互图的输入模型使用了用例图、用例描述、系统顺序图和设计类图。我们称这些设计模型的最终开发结果为用例的实现。在这个例子中,术语实现指的是对每个用例的详细系统过程进行说明,而不是实现用例。换句话说,是制定了软件的蓝图。因此,不仅仅只有面向对象分析是用例驱动的,面向对象的设计也是用例驱动的。也就是说,设计是由一个用例接着一个用例完成的。用例的实现:对每个用例的详细系统过程的说明。面向对象设计中的第三步是,根据开发交互图时得到的信息,回过头来设计类图和开发方法名称。可视化和特征信息也是在设计类图的迭代中被修改的。设计的最后一步是,用包图将设计类图分割成相关的功能。有几种分割系统的方法。一种方法是建立子系统,另一种方法是分层。在第9章中,我们已经学习了多层和多级结构。本章中,我们将学习如何将设计类图分解成多个包,以表示多层系统中不同的层次。我们关注的是基本的多层设计,有可视层(用户界面类)、域层(来自问题域模型类图的问题域类)和数据层(数据访问类)。注意用来表示域层的几个术语。同义术语包括域层、问题域层和业务逻辑层。包图可以使我们从较高的层次去看待最终的系统。10.2设计类和设计类图如图10-4所示,设计类图和详细交互图均使用对方作为设计时的输入,二者的开发过程是平行的。设计类图的第一次迭代是基于域模型和工程设计准则的。初步设计类图用于辅助开发交互图。由于设计决策是在交互图的开发过程中制定的,所以结果又可以用来完善设计类图。正如我们前面提到的,设计类图是面向对象分析时开发的域模型类图的扩展。域模型类图揭示了问题域类和它们之间的联系。由于分析是一个发现的过程,所以分析人员一般不大关心属性或方法的细节。然而在面向对象的程序设计中,类的属性必须被声明成公开的或私有的,每一个属性必须定义类型,比如字符型或数字型。在设计阶段,详细定义这些细节是很重要的,详细定义传递给方法并返回结果的参数也是很重要的。有的时候,分析人员还要定义每种方法的内在逻辑。设计类图是域设计模型类图更详细的体现。我们通过集成来自交互图和其他模型的信息来完成它。当开发者建立设计类图时,还要在以前的域模型的基础上增加很多类。因为设计的目的是了解需求,所以重点是说明定义问题域的类。然而要建立一个完整的面向对象系统,还要定义很多其他设计类。如图10-1所示,输入窗口对象和数据库对象就是这些必须被定义的额外类的例子。当这些类被定义后,我们通常会在不同的类图中证明它们。系统中的类能被分解到各种不同的类图中,比如说用户界面类,同时我们也用子系统来开发各种类图。关键是类图绘制是一种灵活运用的工具。我们现在来介绍开发设计类图的第一次迭代中使用的设计类图符号和设计准则。10.2.1设计类图符号统一建模语言(UML)没有说明设计类符号和域模型符号的区别,但实际上二者是存在区别的,原因主要是由于设计模型和域模型的目标不同。域模型展现的是用户工作环境下的情况,以及它们之间的联系。类不是特指软件类,但是只要我们开始创建设计类图,我们就要定义软件类。因为在设计过程中要定义很多不同类型的设计类,UML使用了一种特殊的符号,叫做构造型,它允许设计者为每一个类指明一个专门的类型。构造型将模型元素以特定的类型分类。通过说明我们想要强调的特征来扩展模型元素的基本定义。构造型的符号就是将类型的名称放到书名符号中,像控制这样。当你开始设计一个用例图的时候,首先要定义一个构造型。前面已经学过,角色和用例之间的连接线表明了一种关系,以及用例之间关系的类型,称为包含关系。这就是一个构造型,因为它把一个用例的关系归类为包含另一个用例。构造型:按照模型元素的特征进行归类的一种方式,用符号描述。有四种类型的设计类被认为是标准的设计类:实体类、控制类、边界类和数据访问类。图10-5展示了用来识别这四种构造型的符号。两种类型的符号可以用于设计类。左边的表示类的方框给出了完整的符号。在每个方框中,名称上方是构造型。右边的圆形符号是这些构造型的速记符号,叫做图标。我们会经常使用这些构造型图标,但是在大多数情况下我们更倾向于使用完整的符号。实体类是问题域类的设计标识符。换句话说,它来自域模型。这些对象通常是被动的,因为它们只是等待事情的发生,通常它们还是持久类。一个持久类在程序结束后仍然存在。也就是说,在系统关闭后这些数据仍要存在。很明显,实现的方法就是将它们写入文件或数据库。图10-5 设计模型中的标准构造型边界类是存在于系统的自动化边界上的。在一个计算机系统中,这些类可以是窗口类或是所有和用户界面有关的其他类。控制类是在边界类和实体类中间起协调作用的类。换句话说,它负责从边界类对象获取信息,然后发送到适当的实体类对象,就像是域层和可视层之间的一个开关或是控制器。 数据访问类是从数据库获取信息或向数据库发送信息的类。不同于向实体类方法中插入数据库访问逻辑(包括SQL语句),在设计中通常包含一个访问数据库的独立的类的层次。 实体类:是问题域类的设计标识符。持久类:程序结束后仍然存在的实体类。 边界类:存在于系统的自动化边界上的类,如输入窗口。 控制类:是在边界类和实体类中间起协调作用的类,在域层和可视层之间起开关控制的作用。 数据访问类:是从数据库获取信息。 10.2.2设计类符号图10-6详细说明了设计类符号。名字部分包括类名和构造型信息。下面的两个部分包含了关于属性和方法更详细的信息。图10-6 定义设计类的内部符号分析员用来定义属性的格式如下:属性可见性(+表示可见,-表示不可见。可见性表示其他对象是否能直接访问这些属性);属性名称;类型表达式(例如,字符型、字符串型、整型、数字型、货币型或日期型);初值;原型(在花括号内),比如关键字。第三部分包含了方法特征信息。方法特征显示了需要调用这个方法的所有信息。它给出了这些要发送消息的格式,包括如下内容:方法可见性;方法名;类型表达式(方法返回参数的类型);方法参数列表(输入参数)。 方法特征:描述调用该方法所需的所有信息的符号。 在面向对象的程序设计中,分析员通过使用完整标识来识别每一个方法。一些面向对象语言允许多个方法使用同一个名称,因此要将它们区分开来,我们就要使用参数表。在这些语言中,需要用方法名和参数表去激活相应的方法。例如,假设我们想通过客户ID或客户名来取得客户记录,那么我们就可以建立两个方法,并为这两个方法起同一个名字,例如,“getCustomer(CustomerlD)”和“getCustomer(CustomerName)”。我们把getCustomer叫做方法重载即这两个方法有同一个名字。想要知道哪个方法被激活,则编译器需要知道包含参数是什么即输入的参数是一个数字(CustomerID)还是一个字符串(customerName)。第7章说明了学生注册系统的域模型的几个类。图10-7进一步比较了域模型学生类和设计类图学生类。域模型属性列表包含了所有在分析活动中发现的属性。设计类图包含了关于属性类型、初值和原型的更多的信息,它也可以包含用来声明的构造型,Student类就是一个实体构造型。在设计类图Student类中,第三部分包含了类的方法特征。大多数方法特征是在设计交互图的时候建立的。记住,UML是一种笼统的面向对象的符号技术,而不是特定的某一种语言。所以,这些符号和程序设计方法中的符号不完全一样。图10-7 域图和设计类图的学生类例子比如,对于有程序设计经验的人来说,使用的构造器符号是CreateStudent:student(name,adress,maior)。构造器是用来建立类的新对象的方法。在很多程序设计语言中,构造器和类有同样的名字。然而,我们使用创建语句来跟踪在交互图中使用的信息名称。图中还说明了另一个构造器。在第二个方法中,只有StudentID被传递进来。这说明一个学生只有ID的信息,构造器要自己填充学生的其他信息。这通常要求访问数据库以获得该字段的值。图中用横线标识出来的叫做findAboveHours(int hours):StudentArray的方法是一种专门的方法。在面向对象方法中,类是创建个体对象和实例的模板。对类的每个实例大多数方法都适用。但是,分析员常常需要立即检查所有的实例。这种类型的方法称为类级方法,它们用下划线表示出来了。在VB.NET里,这种方法称为共享方法;而在Java里,它是静态方法。这种方法是由类而不是由类的某一对象执行的。因为这些方法在类级别应用,它们不依赖于某一对象的存在,如果需要,就可以通过所有的对象访问数据。在这个例子里,findAboveHours方法审查了类的所有例子,返回了那些总小时数比输入参数大的学生队列。 类级方法:与类而不是类的对象相关的方法。 10.2.3一些基本的设计准则既然你已经了解了一个面向对象程序是如何运行的,也学习了设计类的符号,让我们来回顾一些指导设计决策的基本准则。在本章中,我们讨论面向对象设计的步骤时,会提到这些好的面向对象设计的准则。以下的这些基本准则对面向对象设计的每一部分都很重要。封装和信息隐藏封装是一种设计概念,它说明了一个对象包含数据和程序逻辑的独立单元。每个对象都是内部携带自己的数据,并提供访问数据的方法,而且还提供一系列调用对象方法的服务。用这种方法设计软件的一个好处就是软件开发人员可以用搭积木的方式设计系统。几乎所有的工程规范都有像积木块一样的标准单元,它们可以组合形成最终的设计。被封装的对象等价于软件的每一个积木块。封装:是一种设计准则,规定数据和程序逻辑包含在一个独立的单元中。程序员依靠封装带来的好处支持对象重用的思想。每一种面向对象的语言都有一些在系统中被反复使用的标准对象。这些对象的标准集提供了在同一系统中多次使用的基本服务有时甚至是在不同的系统中多次使用。重用的一个最普遍的例子是为计算机或网络应用设计用户界面。设计者通常重用相同的类来开发窗口和诸如按钮、菜单、图标等的窗口部件。问题域类也会被重用。对象重用:是一种设计准则,说明标准对象可以在系统中反复使用。和封装相关的概念是信息隐藏。信息隐藏的意思是,和一个对象有关的数据对外部世界是不可见的。换句话说,对象的属性是私有的。用一组方法来访问和修改数据。虽然这条准则主要是一个程序上的概念,并且主要有利于编程和测试,但它是一些重要准则的基础。如果对数据属性的访问是通过10.2.4节中将要介绍到的方法名称的标准接口来实现,则系统中对象间的联系和耦合会好的多。信息隐藏:是一种设计准则,指和一个对象有关的数据对外部世界是不可见的,通过使用一组方法来访问和修改这些数据。导航可见性就像前面提到的,面向对象系统是相互作用的对象的集合。为了在设计阶段记录两个对象间发生的关系,开发了交互图。但是,如果一个对象通过发消息的方式和另一个对象进行联系,那么第一个对象对于第二个对象来说必须是可见的。这里我们所说的导航可见性,就是指一个对象能够看见另一个对象并与其进行交互的能力。用编程的术语来说,调用某个对象的方法经常需要用点符号来调用合适对象的合适方法。有时开发者直接把导航可见性说成导航,或是可见性。导航可见性:是一种设计准则,指一个对象可以看到另一个对象并与之交互。 设计者必须总是关注导航可见性。对象之间的交互只能通过导航可见性来实现。设计的一个任务就是要说明哪一个对象对哪一个对象有导航可见性。导航可见性可以是单向也可以是双向的,比如,一个Customer对象可以看见一个Order对象,这意味着Customer对象可以知道客户发出了哪些订单。在程序里,Customer类用一个变量或是变量数组来指向这个客户的一个或多个Order对象。如果导航可见性是双向的话,那么Order对象就有指向Customer对象的变量了。如果导航可见性不是双向的,Order对象就没有指向Customer对象的变量。在设计类图里,导航可见性用类之间的箭头表示,箭头指向可见的类。图10-8展示了Customer类和Order类之间的单向导航可见性。注意,在Customer类中有一个叫myOrder的变量。该变量的值指向某个Order实例。通常情况下,变量myOrder并不直接在设计类中出现。导航的箭头就表示一个类对另一个类有可见的要求。而在这个例子中我们添加了这个变量来强调这个概念。图10-8 Customer和Order间的导航可见性耦合耦合这个术语来自导航可见性。在前面的例子中,Customer对Order有导航可见性,也可以说Customer和Order是耦合的,或者是有联系的。现在,在整个系统的所有类中延伸可见性这个概念。耦合是对设计类图中的类与类之间连接关系紧密程度的定性的度量。一种比较容易理解耦合的方法是看设计类图中导航箭头的个数。对系统来说,弱耦合比强耦合好。换句话说,较少的导航可见性箭头说明系统更易于理解和维护。耦合:是对设计类图中的类与类之间连接关系紧密程度的定性的度量。 之所以说耦合是个定性的度量,是因为在系统中并没有一个特定的数字来定量地说明耦合。设计者必须对耦合有一定的理解当耦合太强时,设计者要能够认识到,或者要能够知道什么样的耦合才是合适的。耦合是作为一个设计过程用例被评价的。一般情况下,如果每个用例设计都有合适级别的耦合,那么整个系统也会有比较合适的耦合。我们再回顾一下图10-1,仔细观察对象之间的消息流。很明显,互相通信的对象必须有导航可见性,所以它们就是耦合的。输入窗口对象为了向学生对象发送消息,则它对学生对象必须有导航可见性,所以输入窗口对象和学生对象是耦合的。但是注意,输入窗口对象并没有和数据库对象连接,所以它们之间不是耦合的。如果我们设计一个系统使输入窗口对象也可以访问数据库对象,那么这个用例的整体耦合性将会增加。也就是说,会有更多的连接。这样做是好是坏呢?在这个简单的例子中,这也许不会成为什么问题。但是对一个有10个或是更多用例的系统,无规则的连接和导航可见性会导致很强的耦合,使系统很复杂。那么为什么强耦合性不好呢?主要是因为强耦合增加了系统不必要的复杂性,使系统很难维护。一个类的变化会波及整个系统。所以,有经验的分析员会尽量简化耦合,并降低对新系统设计的影响。任务的聚合和分解聚合指的是一个类中各种功能的一致性。聚合是对一个类中目的单元或主题的定性度量。比如在图10-1中,我们希望学生类有这样的方法或功能,它能够输入学生信息,如学生学号或是名字。这代表了一个目的单元和一个高聚合类。但是如果同一个对象也有分配教室或分配教授的方法呢?类的聚合性就会被减弱。聚合:是对一个类中功能一致性的定性度量。低聚合的类有几个方面的负效应。首先,它们难于维护。因为它们有很多不同的功能,所以对系统内的变化非常敏感,容易产生连锁反应。第二,很难重用这些类。他们有很多不同的(通常是无关的)功能,因此,在其他环境下的重用通常没有意义。比如,一个有按键功能的按钮类经常被重用。但是,有按键功能和用户登录功能的按钮类却很少被重用。最后一个缺点是,没有聚合的类难于理解。通常,它们的功能相互交叉,逻辑非常复杂。虽然聚合性无法用一个度量系统来衡量,但是我们可以把类的聚合性分成极低、低、中等,以及高聚合四种类型。我们最需要的是高聚合类。一个极低聚合的类可以是这样的,它在不同的功能领域都有服务的任务,如一个类既可以访问网络又可以访问数据库。这两种活动是完全不同的,而且是为了达到不同的目的,因此把它们放在一个类里就会造成低聚合性。举个低聚合的例子。这个类可能在相关领域有不同的任务,也可能完成数据库中所有表的数据访问功能。然而,更好的方法是用不同的类来访问用户信息、命令信息和库信息。虽然功能是一样的(就是说这两种方法都访问数据库),但是传入和导出的数据类型是不一样的。所以,与整个数据库连接的类就不像只与用户表连接的类的那样易于重用。举个中等聚合的例子。这个类有联系密切的相关任务,比如,一个记录客户信息和客户账号信息的类。可以定义两个高聚合的类,一个记录客户信息,比如名字和地址;另一个或一组类记录客户账号,比如余额、支出、信用卡信息和所有的财务活动。如果客户信息和账号信息是受限的,它们就被组合到一个中等聚合的类中。在系统设计中,中等聚合或高度聚合的类都是可以接受的。解决低聚合类的普遍方法是把它分成几个高聚合类,这个概念叫做任务分解,是另一个优秀的面向对象设计的准则。任务分解说明在大多数情况下,把不同的任务分配到不同的类中比较好。任务分解是另一种开发高聚合类的方法。任务分解:是一种设计准则,指分析员将一个类划分成几个高聚合的类。 10.2.4开发初步设计类图开始设计时,我们开发基于域模型的初步设计类图。图10-9复述了为第7章所开发的RMO设计的域模型类图。就像在前面学过的一样,分析的重点仍然是确定类、它们的属性,以及类之间的关系。可以通过扩展域模型类图的方法来构造初步设计类图。它需要两个步骤:(1)用类型和初值信息详细描述属性;(2)添加导航可见性箭头。图10-10是RMO的一个设计类图,给出了上述两个步骤的结果。属性的描述非常清晰。类型信息是由设计者根据他的经验决定的。最后,在大多数实例中,所有属性都是不可见的或私有的,在图中用它们前面的负号表示出来。导航可见性设计起来有点困难。记住我们开发的只是初步的类图,所以在设计过程中可以增加或删除导航箭头。在构建导航可见性时,我们提出的基本问题是,要涉及到哪些类或者说要访问哪些类,其他类有哪些?这里有一些常见的规则,不是必须遵守,但通常是这样的。图10-9 RMO域模型类图一对多的关系。它说明了上级/下级关系通常是有上级到下级的导航,比如,从Order到OrderItem。而有的时候这些关系组成了导航链的各个层次,比如,从Catalog到ProductItem再到InventoryItem。强制关系。在这种关系里,一个类的对象在没有另一个类的对象的情况下是不能存在的。这种关系是从相对独立类到不独立类的导航,比如,从Customer到Order。当一个对象需要获取来自另一个对象的信息时,必须有导航箭头指向对象本身或是层次中它的父类。导航箭头可以是双向的。图10-10 RMO初步设计类图正如上面的规则所述,图10-10显示了Customer对Order的导航可见性。Order对OrderItem,OrdeiTransaction和ReturnItern都有导航可见性。Catalog,ProductItem和InventorvItem形成了一个导航链层次,白上向下导航。作为关联类的CatalogProduct对Catalog也要可见。Shipment对Shipper也具有导航可见性。在OrderItem与InventorvItem,OrderItem与Shipment之间的可见性问题上还存在一些无法解决的问题,即用什么样的方法来完成这些类之间的导航效果最好。这些问题也许需要增加符号来解决或是应用其他的设计准则。这里要强调三点问题。第一,因为设计的细节是依靠一个个用例完成的,所以要确保交互图支持并可以完成初始化时定义的导航。第二,导航箭头要随着设计过程进行相应的修改以保持和设计细节的一致。最后,要根据为用例创建交互图时制定的设计决策,为每个类添加方法特征。10.3交互图实现用例和定义方法正如我们在这章的最开始提到的一样,开发交互图是面向对象设计的核心。用例的实现是在交互图的开发过程中完成的,实现用例的过程就是确定哪些类通过发送消息与其他类进行协作的过程。本节的目标就是解释如何使用交互图完成面向对象设计。在设计时要开发两种交互图:顺序图和协作图。用任何一种图都可以完成设计。有些设计者喜欢用顺序图,有些喜欢用协作图。首先我们讨论用顺序图设计,然后解释如何在设计中使用协作图。理解设计系统与对设计过程和决策的结果进行存档之间的区别是很重要的。在软件设计的时候,设计者开发如设计类图和交互图这样的图。这些图向程序员和其他开发者说明了其结构和行为的细节,但图本身并不是目标,相反,它们代表了基于优秀设计准则(如耦合,聚合和分解)的设计决策的结果。典型的例子是,设计者设计草图后,通过评价它们是如何反映优秀设计准则的来评价他们的质量。设计者为了提高质量和纠正错误可能多次修改这些图。这些图既是设计者想法的存储器也是和开发人员者交流这些想法最终结果的方法。正如你学习了交互图一样,你将学习如何设计它。我们将把讨论分散于优秀设计准则中。我们从两个以上的基本准则开始对象职责和用例设计控制器。图10-11是一个类图,它是包含“查询可用条目”用例所需的所有类的一个部分设计类图。用它来说明这两个设计准则。图10-11 “查询可用条目”用例的部分设计类图10.3.1 对象职责面向对象开发的一个基本准则是对象职责的思想,即由对象负责实施系统过程。设计的一个主要活动就是定义对象类的任务。这些任务分为两类:认识和行动。换句话说,一个对象应该知道什么?一个对象应该做或是激起什么?对象职责:是一种由对象负责实施系统过程的设计准则。认识包括这样的任务,如认识自己的数据,认识其他的一起协作执行用例的类。很明显,一个类应该认识自己的数据,存在什么样的属性,怎样维持这些属性的信息,以及到哪里去找需要的信息。比如,在一个对象初始化的时候,某些属性的数据可能作为被调用的构造器的一部分来传递。一个对象应该认识到,也就是说,一个对象应该具有对向它提供信息的对象的导航可见性。比如,在图10-7中,学生类的构造器不接收学生ID值作为参数。学生类负责根据它所知道的某些准则创建一个新的学生ID值。行动包括一个对象所做的支持用例执行的所有活动。一些活动接收和发送信息,另一些对象负责例示或创建完成用例所需的新的对象。类之间要相互协作完成用例的实施。一些类用来统筹协作。例如,对于图10-11中的查询可用条目的用例,Catalog类主要负责处理用例的实施。另一个类,比如InventoryItem类,只负责提供它自己的信息。一个系统设计者大部分重要的活动是决定对象职责并建立基于这些决策的系统。在下面讨论设计的章节中,我们将提供更多关于对象职责和分配职责的例子。分配对象职责的概念成为面向对象设计的一部分已经有很长时间了。在面向对象设计的历史发展中,最流行的分配职责的方法是使用“35”索引卡。这些卡叫CRC卡,即类一任务一协作卡,用来存档系统中的类、类之间相互协作的方法、每个用例中每个类的职责。CRC卡技术仍在很多地方广泛使用,以支持设计过程。 CRC(类-任务-协作)卡:是用来存档系统中的类、类之间相互协作的方法、每个用例中每个类的职责的索引卡。 10.3.2用例控制器通常,每个用例可能含有许多来自外部参与者不同的消息。作为面向对象分析一部分的系统顺序图能够描述出这些输入消息,但只表示这些消息输入到了系统中。然而,在设计过程中,我们必须确定那个对象得到所有的消息。为了简化搜集和处理用例所需要的全部消息的过程,系统设计者通常建立一个新类,这个类用做输入消息的采集点,这些类就叫做用例控制器。例如,对于用例“查询可用条目”,将会产生一个叫做AvailabilityHandler的控制器类。用例控制器完全是系统设计者人为建立的一个类。有时候,这些类也叫做制品,表示某些事物为了特定目的而建立。我们之所以把这些类称做制品,是因为在工业中经常这样使用。其实,制品是一个人为创建的东西。换句话说,本章里创建的设计模型也可以被认为是制品。用例控制器:系统设计者创建的用来作为输入消息收集点的类。 制品:系统设计者创建的用来处理必要的系统功能的类。用例控制器的作用就好比外部世界与内部系统的中间形态。在图10-1中,我们看见输入窗口对象,它位于系统的边界与叫做学生对象的问题域对象之上。假如输入窗口对象要向对象发送消息,那该怎么办呢?这就需要参考所有的问题域对象。输入窗口对象与系统之间的耦合性可能很高,即有很多的连接,因此,用一个用例控制器对象来管理所有的输入消息就能够降低用户交互对象与问题域对象之间的耦合性。有几种方法来建立用例控制器。可以为所有的用例定义一个用例控制器。这时,给这个用例分配的任务会很广泛,而这个类的聚合性却很可能非常低。因此,一个好的设计应该是定义一些用例控制器,每个都被分配一些具体的任务,或者为单一子系统(如订单输入子系统)中的所有用例创建一个用例控制器。多个用例控制器可能会增加用户接口类与内部类之间的耦合性,但是这样能够产生一些高聚合性的类,它们中的每一个都被分配了定义好的任务集。给每个用例建立一个用例控制器的方法也是一个切合实际的选择。图10-11就描述了为单一用例创建的单一用例控制器。这个用例的用例控制器及问题域类都包含在一个设计类图中。注意,这个设计类图只画了导航可见箭头。在前面几段里讲述的思想过程就是系统设计的过程,即在耦合、聚合及类的职责等设计准则间找到一个平衡。在接下来的章节中,我们会详细讨论这个过程。10.4用顺序图设计交互图构成了面向对象设计过程的核心,而顺序图则用来解释对象之间的相互关系,并且记录设计决策。首先,我们复习一下顺序图的结构和句法,然后顺着一些规则和步骤来设计系统。在第7章讲述如何建立一个系统顺序图的时候,我们已经对顺序图有了大致的了解。因此,现在理解顺序图,甚至自己设计一个,都应该是得心应手的了。要记住系统顺序图是用来为一个用例或者一个场景记录系统的输入与输出的。它捕捉了系统与参与者所描述的外部世界之间的相互关系。系统本身就被看做是一个叫做系统的对象。系统的输入就是参与者传递给系统的消息,输出通常是回复的消息,表示数据正在返回。图10-12是图7-11的细化版本,它描述了顺序图的基本组成,并对此做出了解释。我们从一个简单的RMO典型用例查询可用条目开始。如图10-12所示,每个消息都有一个源头与目的地。在顺序图中,由于只有两个对象有生命线,因此消息源与目的地就受到了限制。如果我们详细地分析顺序图的话,那么就要做出一些很重要的决策,即消息源对象及消息目的地对象。在第7章中提到的输入消息的句法如下:*true/false condition return-value:=message-name(parameter-list)而对于输出消息,我们通常只须写出参数表而不要加括号。详细的顺序图和SSD使用相同的元素,差别是:系统中所有的内部对象和消息取代了系统对象。换句话说,对于SSD,系统被看做一个黑箱,我们不知道其内部处理过程。那么设计的目标就是打开这个黑箱,并找到那些在自动化系统中进行的内部处理。正如在图10-1中所述,我们需要辨认出在用例或者用例场景实现过程中的内部对象和消息。注意,前面的分析活动主要是围绕用例展开的,下面的详细设计部分也将如此。图10-12 “查询可用条目”用例的系统顺序图10.4.1初步顺序图基于图10-12中的系统顺序图,我们继续用例查询可用条目的详细设计。扩展系统顺序图的第一个步骤是决定余下的哪一个对象应该参与到用例实现中。系统顺序图指出有关每个条目的返回信息应该包括desc

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论