资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第,*,页,第,11,面向对象的设计与实现,2024年10月30日,第,1,页,第,11,章 面向对象的设计与实现,本章内容结构,本章引言,学习目标,教学内容,本章小结,思考和练习,课堂讨论,本章引言,面向对象分析,OOA,针对现实世界中的问题域与系统职责建立模型,面向对象设计,OOD,是利用面向对象观点建立求解域模型的过程,面向对象的实现是选择一种面向对象的程序设计语言进行编码、测试、审查、调试和优化的过程。,OOA,模型不考虑与系统的具体实现相关的因素。,OOD,则是把分析阶段得到的对目标系统的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。面向对象分析、设计和实现是一个多次反复迭代的过程,这是面向对象方法的一大优点。,本章将讲述面向对象设计与实现过程中的一些问题,包括:设计准则和启发式规则;系统设计;服务、关联和聚合关系设计;设计优化以及面向对象的实现。,2024年10月30日,第,2,页,2024年10月30日,第,3,页,学习目标,掌握面向对象的设计准则和启发式规则,理解和掌握系统设计的方法和步骤,理解和掌握,OOD,中服务、关联与聚合关系设计,了解,面向对象设计优化,了解,面向对象系统实现中的一些注意事项,2024年10月30日,第,4,页,教学内容,11.1,面向对象的设计准则和启发式规则,11.2,系统设计,11.3,服务、关联与聚合关系设计,11.4,面向对象设计优化,11.5,面向对象系统的实现,11.6,本章小结和习题,2024年10月30日,第,5,页,11.1,面向对象的设计准则和启发式规则,11.1.1,面向对象设计准则,11.1.2,启发式规则,2024年10月30日,第,6,页,11.1.1,面向对象设计准则,面向对象设计的过程可以看作是按照设计准则,对分析模型进行细化的过程。面向对象的设计准则包括以下,6,个方面。,1,模块化,对象是面向对象软件系统中的模块,它把数据结构和操作这些数据的方法紧密地结合在一起构成模块。,2,抽象,抽象强调对象的本质、内在的属性,而忽略了一些无关紧要的属性。面向对象的程序设计语言不仅支持过程抽象,而且支持数据抽象。对象类实际上就是具有继承机制的抽象数据类型。此外,某些面向对象的程序设计语言还支持参数化抽象。,11.1.1,面向对象设计准则,3,信息隐藏,在面向对象方法中,信息隐藏具体体现为类的封装性。类是封装良好的可重用构件,类的定义结构将接口与实现分开,软件外部对内部的访问通过接口实现,从而支持信息隐藏。,4,弱耦合,按照抽象与封装性,弱耦合是指子系统之间的联系应该尽可能少。面向对象系统中的耦合包括交互耦合和继承耦合两种类型。,2024年10月30日,第,7,页,11.1.1,面向对象设计准则,(,1,)交互耦合:是对象之间的关联关系的一种形式,交互耦合通过消息连接来实现。交互耦合应尽可能松散,即:一应尽量降低消息连接的复杂程度;二应尽量减少消息中的参数个数,降低参数的复杂程度;三应减少对象发送(或接收)的消息数。,(,2,)继承耦合:是一般化类与特殊类之间耦合的一种形式。继承耦合程度应该尽可能提高,因为从本质上看,通过继承关系结合起来的父类和子类,构成了系统中粒度更大的模块,因此,它们彼此之间应该结合得越紧密越好。为获得紧密的继承耦合,特殊类应该是对其一般化类的具体化。,2024年10月30日,第,8,页,11.1.1,面向对象设计准则,5,强内聚,强内聚指子系统内部各构成元素对完成一个定义明确的目的所做出的贡献程度。面向对象系统中的强内聚包括服务内聚、类内聚和一般,-,特殊内聚。,(,1,)服务内聚指一个服务应该完成一个且仅完成一个功能。,(,2,)类内聚指一个类应该只有一个用途,它的属性和服务应该是高内聚的,也就是说,类的属性和服务应该全都是完成该类对象的任务所必需的,其中不包含无用的属性或服务。实际上,对于面向对象软件来说,最佳的内聚是通信内聚,即一个模块可以完成许多相关的操作,每个操作都有各自的入口点,它们的代码相对独立,而且所有操作都在相同的数据结构上完成。,(,3,)一般,-,特殊内聚指设计出的一般,-,特殊结构应该是对相应的领域知识的正确抽取。一般说来,紧密的继承耦合与高度的一般,-,特殊内聚是一致的。,2024年10月30日,第,9,页,11.1.1,面向对象设计准则,6,可重用,重用是提高软件开发生产率和目标系统质量的重要途径,目前可重用内容大多从设计阶段开始。重用有两方面的含义:一是尽量使用已有的类(包括开发环境提供的类库及以往开发类似系统时创建的类);二是如果确实需要创建新类,则在设计这些新类的协议时,应该考虑将来的可重复使用性。,2024年10月30日,第,10,页,2024年10月30日,第,11,页,11.1.2,启发式规则,面向对象方法学在发展过程中也逐渐积累起一些经验法则,总结这些经验得出了几条启发式规则,它们在面向对象设计中往往能帮助设计人员提高设计质量。,1,设计结果应该清晰易懂,使设计结果清晰、易读、易懂是提高软件可维护性和可重用性的重要措施。保障设计结果清晰易懂的主要因素如下。,(,1,)用词一致:设计中应该使名字与它所代表的事物一致,而且应该尽量使用人们习惯的名字。不同类中相似服务的名字应该相同。,(,2,)使用已有的协议:如果开发同一软件的其他设计人员已经建立了类的协议,或者在所使用的类库中已有相应的协议,则应该使用这些已有的协议。,11.1.2,启发式规则,(,3,)减少消息模式的数目:如果已有标准的消息协议,涉及人员应该遵守这些协议。如果确需自己建立消息协议,则应该尽量减少消息模式的数目,只要可能,就使消息具有一致的模式,以利于读者理解。,(,4,)避免模糊的定义:一个类的用途应该是有限的,而且应该从类名可以较容易地推导出它的用途。,2024年10月30日,第,12,页,11.1.2,启发式规则,2,一般,-,特殊结构的深度应适当,应该使类等级中包含的层次数适当。一般说来,在一个中等规模(大约包含,100,个类)的系统中,类等级层次数应保持为,72,。不应该仅仅从方便编码的角度出发随意创建子类,,应该使一般,-,特殊结构与领域知识或常识保持一致。,3,设计简单的类,经验表明,如果一个类的定义不超过一页纸(或两屏),则这个类比较容易使用。为使类保持简单,应该做到以下几点:不要包含过多的属性;类有明确的定义,即分配给每个类的任务应该简单;尽量简化对象之间的合作关系,不要提供太多的服务。,2024年10月30日,第,13,页,11.1.2,启发式规则,4,使用简单的协议,一般说来,消息中的参数不要超过,3,个。经验表明,通过复杂消息相互关联的对象是紧耦合的,对一个对象的修改往往导致其他对象的变化。,5,使用简单的服务,通常,面向对象设计的类中的服务都很小,可以用仅含一个动词和一个宾语的简单句子描述它的功能。,6,把设计变动减至最小,通常,设计的质量越高,设计结果保持不变的时间就越长。即使出现必须修改设计的情况,也应该使修改的范围尽可能小。理想的设计变动曲线如图,11.1,所示。,2024年10月30日,第,14,页,11.1.2,启发式规则,2024年10月30日,第,15,页,2024年10月30日,第,16,页,11.2,系统设计,在面向对象设计中,大多数面向对象系统的逻辑设计模型可以划分为,4,部分,分别对应组成目标系统的,4,个子系统,即问题域子系统、人机交互子系统、任务管理子系统和数据管理子系统。本节就从这,4,个子系统的设计角度出发,分别介绍各子系统的设计原则和注意事项。,11.2.1,问题域子系统设计,11.2.2,人机交互子系统设计,11.2.3,任务管理子系统设计,11.2.4,数据管理子系统设计,2024年10月30日,第,17,页,11.2.1,问题域子系统设计,通过面向对象分析所得出的问题域精确模型,为设计问题域子系统奠定了良好的基础,建立了完整的框架。只要可能,就应该保持面向对象分析所建立的问题域结构。通常,面向对象设计仅需从实现角度对问题域模型做一些补充或修改,主要是增添、合并或分解类、属性及服务,调整继承关系等。当问题域子系统过于复杂庞大时,应该把它进一步分解成若干个更小的子系统。问题域子系统设计可以对应到面向对象分析中所划分的主题部分,因此也称为主题部件设计。,11.2.1,问题域子系统设计,(,1,)为复用设计与编程的类而增加结构,如果,OOA,识别和定义的类是本次开发中新定义的,那就需要进行从头开始设计。如果已存在一些可复用的类,而且这些类既有分析、设计时的定义,又有源程序,那么复用这些类即可提高开发效率与质量。注意可复用的类可能只是与,OOA,模型中的类相似,而不是完全相同,因此需对其进行修改。设计目标是尽可能使复用成分增多,新开发的成分减少。,另外,现有的若干类中,如果有某几个类有相似性,则可以将所有的具有相似协议的类组织在一起,抽取其共同特征,提供通用的协议,增加一个父类。,2024年10月30日,第,18,页,11.2.1,问题域子系统设计,(,2,)按编程语言调整继承关系,一般地,,OOA,强调如实地反映问题域,而,OOD,要考虑实现问题。在实现领域中,面向对象编程语言有些不支持多继承,所以在,OOD,中,需要按照所选择的编程语言调整分析结果中的继承关系。,(,3,)提高性能,为提高系统整体性能,可以从以下几个方面考虑:把需要频繁交换信息的对象尽量地放在一台处理机上;增加属性或类,以保存中间结果;提高或降低系统的并发度,可能要人为地增加或减少主动对象;合并通信频繁的种类。,2024年10月30日,第,19,页,11.2.1,问题域子系统设计,【,例,11.1】,根据上述原则进行类设计的合并前后对照示意图参见图,11.2,。,2024年10月30日,第,20,页,11.2.1,问题域子系统设计,(,4,)为编程方便增加底层成分,通过细化对象的分类来实现。,【,例,11.2】,将几何图形分成多边形、椭圆、扇形等特殊类型图形,通过继承关系实现这几个图形类之间的联系,参见图,11.3,。,2024年10月30日,第,21,页,11.2.1,问题域子系统设计,(,5,)对复杂关联的转化并决定关联的实现方式。,【,例,11.3】,把多对多关联转化为一对多关联,参见图,11.4,。,2024年10月30日,第,22,页,11.2.1,问题域子系统设计,【,例,11.4】,把多元关联转化为二元关联,参见图,11.5,。,2024年10月30日,第,23,页,11.2.1,问题域子系统设计,(,6,)调整与完善属性,按照语法:可见性属性名:类型,=,初始值对属性的定义进行完善。每一个属性或者包含单个值,或者包含作为一个整体的密切相关的一组值,参见图,11.6,。,2024年10月30日,第,24,页,11.2.1,问题域子系统设计,若要给出对属性的性质的约束,如“工龄,60”,或“,0,英语成绩,100”,等,也要看语言是否对其直接支持,否则要在算法上考虑如何实现。如果编程语言限制了可用的属性类型,则要通过操作的算法来调整。,2024年10月30日,第,25,页,11.2.1,问题域子系统设计,(,7,)构造或优化算法,调整服务,对于需要设计的操作,要从如下几方面进行详细地定义。, 按照定义操作的格式:可见性操作名(参数列表):返回类型完善操作的定义。, 从问题域的角度,根据其责任,考虑实现操作的算法,即对象是怎样提供操作的。, 若操作有前后置条件或不变式,考虑编程语言是否予以支持。若不支持,在操作的方法中要予以实现。,2024年10月30日,第,26,页,11.2.1,问题域子系统设计, 建议进一步分析特定类对象相关的所有交互图,找出所有与之相关的消息。一个对象所要响应的每个消息都要由该对象的操作处理,其中的一个操作也可能要使用其他操作。如果类拥有状态图,还可根据内部转换及外部转换的动作等,设计算法的详细逻辑。可用自然语言或伪代码描述算法,也可以使用程序框图或活动图描述算法。, 在算法中还要考虑对异常和特殊情况的处理。如考虑对输入错误、来自中间件或其他软硬件的错误消息,以及其他例外情况的处理。, 在系统较为复杂或需要处理大批量数据的情况下,若系统在性能上有要求,就要对系统的体系结构和算法进行优化。,2024年10月30日,第,27,页,11.2.1,问题域子系统设计,(,8,)其他,在,OOD,的问题域部分,根据情况,还有一些其他需要考虑的问题。例如,为数据存储管理增补属性与服务;决定对象间的可访问性;考虑加入进行输入数据验证这样的类等。另外,还应该根据具体问题考虑使用合适的设计模式。,当两个子系统互相通信时,可建立客户机,/,服务器(,C/S,)结构或对等结构(,P2P,)。在,C/S,结构中,每个子系统只承担一个由客户机端或服务器端隐含的角色,服务只是单向地从服务器端流向客户机端;在,P2P,结构中,服务可以双向流动。在划分子系统时,往往进行分层设计。系统的每一层包含一个或多个子系统,表示完成系统功能所需的功能性的不同抽象层次。抽象级别由与其相关的处理对用户的可见程度来确定。关于子系统之间通信架构的详细设计信息可参考本书第,13,章内容。,2024年10月30日,第,28,页,2024年10月30日,第,29,页,11.2.2,人机交互子系统设计,人机界面部分的好坏直接影响用户的情绪和工作效率。使用原型支持的系统化的设计策略,是成功地设计人机交互子系统的关键。此外,把人机交互部分作为系统中一个独立的组成部分进行分析和设计,有利于隔离界面,支持系统的变化对问题域部分的影响。,在,OOA,阶段给出了系统所需的属性和操作,已经对用户的界面需求做了初步分析。在,OOD,过程中,应该对目标系统的人机交互子系统进行相应设计,以确定人机交互界面的细节,其中包括指定窗口和报表的形式,设计命令层次等内容。根据需求把交互细节加入到用户界面设计中,包括人机交互所必需的实际显示和输入。用户界面设计部分主要由以下几个方面组成。,11.2.2,人机交互子系统设计,1,用户分类,对用户的分类可以有多种标准,如按组织层次分为高层领导、中层领导、技术骨干、办事员;按职能分为技术类、管理类;按照用户使用系统的目的分为顾客、职员、维护人员等;不同分类标准可以提供界面设计的不同要求。,2,描述与系统交互的参与者的脚本,对前面定义的每类用户分类考虑其目的、特点、操作熟练程度、任务要求等因素。,2024年10月30日,第,30,页,11.2.2,人机交互子系统设计,3,设计详细的交互,人机界面的设计准则包括:, 易学、易用、操作方便;, 尽量保持一致性;, 及时提供有意义的反馈;, 使用户的注意力集中在当前的任务上而不是界面上;, 尽量减少用户的记忆负担;, 具有语境敏感的帮助功能;, 减少重复的输入和操作;, 对用户的操作具有容错性,如具有撤销功能;, 防止灾难性的错误;,其他:如艺术性、趣味性、风格、视感等。,2024年10月30日,第,31,页,11.2.2,人机交互子系统设计,4,设计命令层,除了图形化界面外,对于命令层的设计需要考虑以下问题:, 把使用最频繁的操作命令放在最前面,其他命令按照用户工作步骤排列;, 通过逐步分解,对命令层中的操作适当分块,按照“每次记忆,3,块,每块,3,项”的特点,把深度尽量限制在,3,层以内;, 尽量减少操作步骤,把点击、拖动和键盘操作减到最少。,5,设计人机交互类,首先设计组织窗口和相关部件的用户界面类,用同样的类初始化系统中其他人机交互部件类,保证整个系统人机交互界面的一致性。,6,继续做原型,系统原型是人机交互设计中的重要工作之一,通过快速原型工具或应用构造器尽快做出原型让用户试用,可以快速得到用户反馈,帮助界面设计更符合用户需求。,2024年10月30日,第,32,页,2024年10月30日,第,33,页,11.2.3,任务管理子系统设计,构成一个系统的各组成部分之间经常会存在相互依赖现象,因此任务管理子系统的一项重要工作就是确定哪些对象是必须同时动作的,哪些对象是相互排斥的,然后根据问题域任务描述,进一步设计任务管理子系统。,Coad,和,Yourdon,建议通过下列步骤来设计管理并发任务的对象策略:,(,1,)确定任务的特征(如事件驱动、时钟驱动等);,(,2,)定义协调者任务和关联的对象;,(,3,)集成协调者和其他任务。,11.2.3,任务管理子系统设计,两种最常见的任务是事件驱动任务和时钟驱动任务。事件驱动任务是指可由事件来激发的任务,常常是一些负责与硬件设备、屏幕窗口、其他任务或子系统进行通信的任务;时钟驱动任务是指以固定的时间间隔激发某种事件来执行相应处理的任务,例如,某些设备需要周期性地获得数据,某些人机接口、子系统、任务或处理器需要与其他系统进行周期性通信等,所以产生了时钟驱动任务。,2024年10月30日,第,34,页,11.2.3,任务管理子系统设计,此外,还可以根据任务优先级来安排各个任务,高优先级的任务必须能够立即访问系统资源,高关键性的任务即使在资源可用性减少或系统处于退化的状态下,也必须能够立即运行。当系统中包含,3,个以上的任务时,就应该考虑增加一个任务,专门用来协调任务之间的关系,该任务被称为协调任务。这些协调任务可为封装不同任务之间的协调控制带来好处,该任务的行为可用状态转换矩阵来描述。,2024年10月30日,第,35,页,11.2.3,任务管理子系统设计,除了上述任务外,在任务管理子系统中,还可能会涉及资源使用矛盾的问题,这时需要设计者综合考虑各种因素,以决定在最高性价比条件下实现资源的合理调配和使用。例如,考虑同样功能要求的硬件和软件实现时,设计者必须综合权衡一致性、成本和性能等因素,还要考虑未来的可扩充性和可修改性等,设计合理的选择方案。,2024年10月30日,第,36,页,2024年10月30日,第,37,页,11.2.4,数据管理子系统设计,图,2.3,库存管理系统的系统流程图,数据管理部分包括两个不同的关注区域:对应用本身关键的数据管理和创建用于对象存储和检索的基础设施。数据管理部分提供在特定的数据管理系统中存储和检索对象的基本结构,包括对永久性数据的访问和管理。数据管理部分主要负责存储问题域的持久对象、封装这些对象的查找和存储机制,以及为了隔离数据管理系统对其他部分的影响,使得选用不同的数据管理系统时,问题域部分基本相同。选用不同的数据管理系统,对数据管理部分的设计有不同的影响。,11.2.4,数据管理子系统设计,数据管理子系统的设计首先要根据问题范围选择数据存储管理模式,然后针对选定的管理模式设计数据管理子系统,下面分别进行阐述。,1,选择数据存储管理的模式,目前,可供选择的数据存储管理模式主要有,3,种,即文件管理系统、关系数据库管理系统和面向对象数据库管理系统。设计者应根据应用系统的特点来选择合适的数据存储管理模式。,(,1,)文件管理系统,一般地,文件管理系统提供基本的文件处理和分类能力,特点是能够长期保存数据,成本低,简单。但文件操作的级别很低,使用文件管理数据时还必须编写额外的代码,而且不,同的操作系统的文件管理系统往往有很大差异。,2024年10月30日,第,38,页,11.2.4,数据管理子系统设计,(,2,)关系数据库管理系统,关系数据库管理系统通过若干二维表格来管理数据,其中,二维表由行和列组成,一个关系数据库由多张表组成。关系数据库管理系统的理论基础是关系代数,在多年的发展完善中,关系数据库管理系统能够提供最基本的数据管理功能,支持标准化的,SQL,语言,可以为多种应用提供一致的接口,但是其缺点也比较明显,包括运行开销大、不能满足高级应用需求、与程序设计语言连接不自然等。,(,3,)面向对象数据库管理系统,面向对象数据库管理系统是一种新技术,有两方面的特征,一是面向对象的,应支持对象、类、操作、属性、继承、聚合、关联等面向对象的概念;二是它具有数据库系统所应具有的特定和功能,因此,面向对象数据库管理系统通常通过扩充关系型数据库管理系统或扩充面向对象编程语言的方式来实现。其产品大概分,3,类。,2024年10月30日,第,39,页,11.2.4,数据管理子系统设计, 在面向对象编程语言的基础上,增加数据库管理系统的功能,即长久地存储、管理和存取对象的语法和功能。, 对关系数据库管理系统扩充抽象数据类型和继承性,再增加一些一般用途的操作供创建和操作类与对象等,使之支持面向对象数据模型,并向用户提供面向对象的应用程序接口。, 第三种是按“全新的”面向对象数据模型进行的设计。由对象数据库管理组,ODMG,提出的一些数据库标准正在逐渐地得到广泛的接受,如对象定义语言(,Object Definition Language,,,ODL,)是一种描述对象数据库结构和内容的语言。,2024年10月30日,第,40,页,11.2.4,数据管理子系统设计,2,设计数据管理子系统,针对选定的数据存储管理模式,数据管理子系统的设计包括数据格式设计和相应服务设计两部分。,(,1,)数据格式设计,下面分别介绍每种管理模式的数据格式设计的方法和步骤。 文件管理系统:列表给出每个类的属性,将所有属性表格规范化为第一范式,为每个类定义一个文件,然后测量性能和需要的存储容量是否满足实际性能要求,若文件太多,就要考虑把一般,-,特殊结构的类文件合并成一个文件,必要时还需要把某些属性组合起来,通过处理时间来减小所需要的存储空间。,2024年10月30日,第,41,页,11.2.4,数据管理子系统设计, 关系数据库管理系统:列出每个类的属性表,将所有属性表格规范化为第三范式,为每个类定义一个数据库表,然后测量性能和需要的存储容量是否满足实际性能要求,若不满足则修改部分表设计到较低范式,通过存储空间来换取时间方面的性能指标。, 面向对象数据库管理系统:对于在关系数据库上扩充的面向对象数据库管理系统,其处理步骤与关系数据库管理系统的处理步骤类似;对于由面向对象编程语言扩充的面向对象数据库管理系统,由于数据库管理系统本身具有把对象映射成存储值的功能,不需要对属性进行规范化;对于新设计的面向对象数据库管理系统,系统本身就包含了合理的数据格式。,2024年10月30日,第,42,页,11.2.4,数据管理子系统设计,(,2,)服务设计,如果某个类的对象必须要存储起来,则在类中应增加一个属性和服务,用于完成存储自身的操作。按照面向对象设计的思想,这种属性和服务可以定义在对应类的构造函数中,这样相应类的对象就知道怎样存储自己的属性和服务,在数据管理子系统和问题域管理子系统之间自动架构必要的桥梁。,2024年10月30日,第,43,页,11.2.4,数据管理子系统设计,不同数据存储管理系统的服务设计要点如下。, 文件管理系统:被存储的对象需要知道打开哪些文件,在文件中如何定位,如何检索出旧值及如何更新它们。此外还需要定义一个,ObjectServer,类,并通过该类对象提供下列服务:通知对象保存自己;检索已存储的对象(查找、读取值、创建并初始化对象等),以便由其他子系统使用这些对象。文件管理系统的访问常常采用批处理方式以提高效率。, 关系数据库管理系统:对象必须确定访问哪些数据库表,如何检索到所需要的元组,如何检索出旧值及如何更新它们。为此也需要定义一个,ObjectServer,类,并通过该类对象提供下列服务:告知对象如何存储自己;检索已存储的对象(查找、读取值、创建并初始化对象等),以便由其他子系统使用这些对象。,2024年10月30日,第,44,页,11.2.4,数据管理子系统设计, 面向对象数据库管理系统:对于在关系数据库上扩充的面向对象数据库管理系统,其使用方法与关系数据库管理系统的使用方法类似;对于由面向对象编程语言扩充的面向对象数据库管理系统,无需增加服务,这种数据库管理系统已经给每个对象提供了存储自己的行为,只需给需要长期保存的对象加个标记,这类对象的存储和恢复即可由面向对象数据库管理系统负责完成;对于新设计的面向对象数据库管理系统,系统本身就包含了相关的服务。,2024年10月30日,第,45,页,2024年10月30日,第,46,页,11.3,服务、关联与聚合关系设计,面向对象分析的模型,通常不详细描述类中的服务及类与类之间的关联关系。面向对象设计则是扩充、完善和细化模型的过程。设计和细化类中的服务、关联关系是设计阶段的一项重要工作。,11.3.1,服务设计,11.3.2,关联设计,11.3.3,聚合关系设计,2024年10月30日,第,47,页,11.3.1,服务设计,面向对象设计中服务的设计可以分为两个步骤:确定类中应有的服务、设计实现服务的方法。,1,确定类中应有的服务,当软件系统开发进行到分析与设计阶段后,需要综合考虑分析阶段的,4,种模型才能正确确定类中应有的服务。一般地,实现模型与服务的关系不大,可以忽略实现模型对服务的影响。对象模型是进行对象设计的基本框架,但是分析阶段得到的对象模型通常只在每个类中列出了很少的几个最核心的服务,设计者需要把动态模型中对象的行为和用例模型中的用例(数据处理)转换成由适当的类所提供的服务。,11.3.1,服务设计,(,1,)从对象模型中引入服务,根据面向对象分析与设计阶段可以平滑过渡的原理,分析阶段对象模型中所包含的服务可直接对应到设计阶段的服务,只是需要比分析阶段更详细地定义这些服务。,(,2,)从动态模型中确定服务,一般地,一张状态图描绘一类对象的生存周期,图中的状态转换就是执行对象服务的结果。对象接收到事件请求后会驱动对象执行服务,对象的动作既与事件有关,也与对象的状态有关,因此,完成服务的算法自然也与对象的状态有关。如果一个对象在不同状态可以接收同样的事件,而且在不同状态接收到同样事件时其行为不同,则实现服务的算法需要有一个依赖于状态的多分支控制结构来实现服务的算法。,2024年10月30日,第,48,页,11.3.1,服务设计,(,3,)从用例模型中确定服务,用例图中的用例表达了数据的加工处理过程,这些加工处理可能与对象提供的服务相对应,因此需要先确定操作的目标对象,然后在该对象所属的类中定义相应的服务。如果某个服务特别复杂而庞大时,可以考虑将复杂的服务分解为简单的服务以方便实现,当然分解过程要符合分解的原理,分解后要易于实现。,2024年10月30日,第,49,页,11.3.1,服务设计,2,设计实现服务的方法,设计实现服务的方法主要包括以下几项工作。,(,1,)选择数据结构,分析阶段,分析人员只需考虑系统需要的逻辑结构,而在面向对象设计中,则需要选择能够方便、有效实现算法的物理数据结构。多数面向对象程序员设计语言都提供了基本的数,据结构,方便用户选择使用。,2024年10月30日,第,50,页,11.3.1,服务设计,(,2,)定义内部类和内部操作,基于分析阶段的模型,在进行面向对象设计时,有时需要添加一些在需求陈述中没有提到的类,这些新增加的类主要用来存放在执行服务操作过程中的中间结果。此外,分解复杂服务和操作时,常常需要引入一些新的低层操作,这些都属于需要重新定义的内部类和内部操作。,(,3,)设计实现服务的算法,面向对象设计阶段应该给出服务的详细实现算法,在此过程中需要综合考虑以下因素。, 算法复杂度。通常选用复杂度较低(效率较高)的算法,但也不要过分追求高效率,应以能满足用户需求为准。, 容易理解与实现。容易理解与实现往往和高效率是一对矛盾,设计者需要权衡利弊,在两者之间找一个折中点,综合考虑各种因素,选择适当的算法。, 易修改和易维护。设计者应该尽可能预测将来可能做的修改和维护,并在设计时提前做些准备。,2024年10月30日,第,51,页,2024年10月30日,第,52,页,11.3.2,关联设计,对象模型中,关联是连接不同对象的纽带,指定对象相互之间的联系路径。分析阶段给出的关联可能是笼统的关联关系,在设计阶段就需要对关联关系进行细化的分析和设计。在此过程中,首先要做的就是确定优先级,分析关联关系是单向关联还是双向关联,然后对关联命名,标注关联中的类的角色,需要的时候可以补充关联类及其属性,关联的约束及关联的限定符。,UML,中对象关联的一般表示如图,11.7,所示。在对象类图上,关联用一条把对象类连接在一起的实线表示。一个关联至少有两个关联端,每个关联端连接到一个类,关联端是有顺序的。关联线旁可以标出关联的名字,线旁的小实心三角箭头表示关联的方向,从源对象类指向目标对象类,关联的方向也可以在关联端加上箭头表示。,11.3.2,关联设计,2024年10月30日,第,53,页,11.3.2,关联设计,(,1,)单向关联与双向关联,关联可以分为单向关联与双向关联,若无方向箭头,则表示双向关联,箭头表示关联的指向。图,11.8,和图,11.9,分别给出了两个对象类之间的单向关联和双向关联的,UML,表示。对于单向关联,类,A,为关联的源类,类,B,为关联的目的类,表示类,A,的属性中包含了一个或多个类,B,的属性。对于双向关联则类,A,属性和类,B,属性中分别包含了对方的一个或多个属性。,2024年10月30日,第,54,页,11.3.2,关联设计,(,2,)关联的命名,若给关联加上关联名来描述关联的作用,则关联在语义上更加明确。图,11.10,是使用关联名的一个例子,其中,Company,类和,Person,类之间的关联如果不使用关联名,则可以有多种解释,如,Person,类可以表示是公司的客户、雇员或所有者等。但如果在关联上加上,Employs,这个关联名,则明确表示,Company,类和,Person,类之间是雇佣(,Employs,)关系。关联名通常是动词或动词短语。关联命名的原则是命名有助于模型的理解,若一个关联意思已经明确,则不需关联名。在关联端可以标出多重性,其表示方法与类属性的多重性描述方法相同。关联端的多重性标记规定该对象类中有多少个对象参与该关联,常用的多重性标记有“,0.1”,、“,1”,、“*”等 。,2024年10月30日,第,55,页,11.3.2,关联设计,2024年10月30日,第,56,页,11.3.2,关联设计,(,3,)角色,在关联的对象类图标旁可以标出类的角色名(,Role,)。角色表示被关联的类参与关联的特定的行为。角色名可以后跟一个冒号“:”和类名。这个类名常是一个接口或类型(,Type,)的名字,表示该角色在关联中的行为是通过相关的接口或类型实现的。角色名前可以标有可视性标记“,+”,、“,#”,、“,-”,等。可视性标记的含义与类属性的可视性标记类似,“,+”,表示属性为公共属性,“,#”,表示属性为保护属性,“,-”,表示属性为私有属性。,关联两端的类可以某种角色参与关联。例如,在图,11.11,中,,Company,类以,employer,的角色、,Person,类以,employee,的角色参与关联,,employer,和,employee,称为角色名。如果在关联上没有标出角色名,则隐含地用类的名称作为角色名。,角色也具有多重性(,multiplicity,),表示可以有多少个对象参与该关联。在图,11.11,中,雇主(公司)可以雇佣多个雇员,表示为,0.n,;雇员只能被一家雇主雇佣,表示为,1,。,2024年10月30日,第,57,页,11.3.2,关联设计,(,4,)关联类及其属性,关联本身也可以有属性,通过关联类可以进一步描述关联的属性、操作及其他信息。关联类通过一条虚线和关联连接。图,11.12,中的,Contract,类是一个关联类,,Contract,类中有属性,duty,,这个属性描述的是,Company,类和,Person,类之间的关联的属性。,2024年10月30日,第,58,页,11.3.2,关联设计,由于指定了关联角色的名字,由类图转换为代码的框架中就直接用关联角色名作为所声明的变量的名字,如,employer,为类,Company,的变量名,,employee,为类,Person,的变量名等。另外,,employer,的可见性是,protected,,也在生成的代码框架中体现出来。因为指定关联的,employee,端的多重性为,n,,所以在生成的代码框架中,,employee,是类型为,Person,的数组,关联类,Contract,有自己独立的属性。,2024年10月30日,第,59,页,11.3.2,关联设计,2024年10月30日,第,60,页,11.3.2,关联设计,(,5,)关联的约束,关联还可以加上一些约束,以加强关联的含义。图,11.13,所示是两个关联之间存在异或约束的例子,即,Account,类或者与,Student,类有关联,或者与,College,类有关联,但不能同时与,Student,类和,College,类都有关联。,约束是,UML,中的,3,种扩展机制之一,另外两种扩展机制是版型(,Stereotype,)和标记值(,Tagged Va lu e,)。约束不仅可以作用在关联,也可以作用在其他建模元素上。,2024年10月30日,第,61,页,11.3.2,关联设计,2024年10月30日,第,62,页,11.3.2,关联设计,在关联端紧靠源对象类图标处可以有限定符,这种关联称为限定关联。限定符有名字或标识,代表被关联的对象的一个属性或多个属性的列表。限定符包含在一个小矩形框内,限定符的名字可以缺省。限定符的作用就是在给定关联一端的一个对象和限定符值以后,可确定另一端的一个对象或对象集。使用限定符的例子如图,11.14,所示,表示一个,User,可以在,Bank,中有多个,Account,。但给定一个,Account,值后,就可以对应一个,User,值,或者对应的,User,值为,Null,,因为,User,端的多重性为,0.1,。这里的多重性表示的是,User,和(,Bank,,,Account,)之间的关系,而不是,User,和,Bank,之间的关系。即:,(,Bank,,,Account,),0,个或者,1,个,User,User,多个(,Bank,,,Account,),2024年10月30日,第,63,页,11.3.2,关联设计,但图,11.14,没有表明,User,类和,Bank,类之间是一对多的关系还是一对一的关系,既可能一个,User,只对应一个,Bank,,也可能一个,User,对应多个,Bank,。如果一定要明确一个,User,对应的是一个,Bank,还是多个,Bank,,则需要在,User,类和,Bank,类之间另外增加关联来描述。图,11.15,表示一个,User,可以对应一个或多个,Bank,。,限定符是关联的属性,而不是类的属性。在实现图,11.14,中的结构时,,Account,可能是,User,类中的一个属性,也可能是,Bank,类中的一个属性或其他类中的一个属性。,引入限定符可以将多重性从,n,降为,1,或,0.1,,做查询操作,则返回的对象最多是一个,如果查询操作的结果是单个对象,则查询操作的效率较高。,2024年10月30日,第,64,页,11.3.2,关联设计,2024年10月30日,第,65,页,11.3.2,关联设计,(,7,)关联的种类,按照关联所连接的类的数量,类之间的关联可分为自返关联、二元关联和,N,元关联共三种关联,其中二元关联是两个类之间的关联,前面已经介绍。递归关联是一个类与自身的关联,即同一个类的两个对象间的关联。自返关联虽然只有一个被关联的类,但有两个关联端,每个关联端的角色不同。图,11.16,给出了一个递归关联的例子。当,Rose,或,Visio,等工具将此递归关联类图转换为代码框架时,在,ElectronicPart,类中产生,ElectronicPart,类型的变量,ElectronicPart ,。,2024年10月30日,第,66,页,11.3.2,关联设计,N,元关联是在,3,个或,3,个以上类之间的关联。三元关联的例子如图,11.17,所示,,Company,、,Trader,、,Commodity,这,3,个类之间存在三元关联,而,Orderform,类是关联类。,N,元关联中多重性的意义是:在其他,N-1,个实例值确定的情况下,关联实例元组的个数。图,11.17,所示的三元关联中,在某个公司(,Company,)和交易者(,Trader,)中可以有多种商品(,Commodity,),对于一个公司提供的一种商品,可以有多个交易者订货,对于一个交易者需要的一种商品,可以向多个公司订货,一个交易者可以从一个公司中订购多种产品。订单(,Orderform,)是图,11.17,三元关联的关联类。,2024年10月30日,第,67,页,11.3.2,关联设计,2024年10月30日,第,68,页,11.3.2,关联设计,在,UML,的规范说明中,用菱形表示,N,元关联建模元素。,N,元关联没有限定符的概念,也没有聚集、组合等概念。,图,11.18,给出了一个对象类图及其关联的示例,图中包含了对象关联、继承、聚集等关系。图中的对象类包括,Order,(订货)、,OrderLine,(订货线)、,User,(用户)、,IndividualUser,(个人用户)、,CoUser,(协作用户)、,Employee,(雇员)、,Product,(产品)、,Hardware,(硬件产品)、,Software,(软件产品)等。,2024年10月30日,第,69,页,11.3.2,关联设计,2024年10月30日,第,70,页,11.3.2,关联设计,图中存在着多个关联关系,从图中可知一个协作用户可与一个或零个雇员联系,一个雇员可以与多个协作用户联系。对象类“用户”与“个人用户”、“协作用户”之间存在着继承关系。在“个人用户”类图标下面的文字串“,creditRating,(),= =”poor”,是对该类的一个约束,说明凡列入“个人用户”类的对象都是一些信誉等级差(,Poor,)的用户。在类“订货线”和类“雇员”的关联分别标有文字串“,Product”,和“,Salerep”,,这些附加的文字串说明该类在关联中的角色。,2024年10月30日,第,71,页,2024年10月30日,第,72,页,11.3.3,聚合关系设计,聚合(聚集和组合)是表达类与类之间组成关系的一种特殊的关联关系描述,根据,组成类,的部分类和整体类之间生存周期是否一样又可以细分为聚集和组合,其中,形成聚集,关系的,类之间生存周期不一定相同,但组合关系的类之间具有相同的生存周期,。,图,11.19,和图,11.20,分别给出了聚集关系和组合关系的两个例子。,11.3.3,聚合关系设计,图,11.19,中的,Book,类和,Style,类之间是聚集关系。一本书可以有色彩及尺寸这些样式(,Style,)方面的属性,可以用一个,Style,对象表示这些属性,但同一个,Style,对象也可以表示别的对象(如图片(,Picture,)的一些样式方面的属性,也就是说,,Style,对象可以用于不同的地方。如果,Book,这个对象不存在,不一定意味着,Style,这个对象也不存在了。,图,11.20,中的,Book,类和,Chapter,类之间是组合关系。一本书可以由章节内容确定,若书不存在,那么表示这本书内容的章节也就不存在,所以,Book,类和,Chapter,类是组合关系。,2024年10月30日,第,73,页,11.3.3,聚合关系设计,在复杂系统中,聚集可以有层次结构。图,11.21,给出了个人计算机系统聚集的层次结构表示。个人计算机系统(,Personal Computer,)是由主机箱、键盘(,Keyboard,)、鼠标(,Mouse,)、显示器(,Monitor,)、,CD-ROM,驱动器、一个或多个硬盘驱动器(,Hard Drive,)、调制解调器(,Modem,)、软盘驱动器(,Disk Drive,)、打印机(,Printer,)组成,还可能包括几个音箱(,Speaker,)。而主机箱内除,CPU,外还带着一些驱动设备,例如,显示卡(,Graphics Card,)、声卡(,Sound Card,)和其他构件。,按照聚集关系的表示法,“整体”类(例如,个人计算机系统)位于层次结构的最顶部,以下依次是各个“部分”类。整体和部分之间用带空心菱形箭头的连线连接,箭头指向整体。,2024年10月30日,第,74,页,11.3.3,聚合关系设计,图,11.21,表示了个人计算机系统的组成,聚集关系构成了一个层次结构。,2024年10月30日,第,75,页,11.3.3,聚合关系设计,聚集与组合表示的部分,/,整体结构关系对系统建模具有重要的作用,这表现在以下两个方面。,(,1,)简化了对象的定义:一个复杂的对象,可以把它的部分特征(属性和操作)分离出来,建立独立的代表部分的对象,形成聚集或组合关联结构,简化了原来整体对象的定义,有利于对复杂事物的分析和理解,减少出错的可能性。,(,2,)支持软件重用:聚集与组合结构支持软件重用。如果在两个或多个对象类中都有一组属性和操作是它们共同的组成部分,则可以把其分离出来,建立独立的代表部分的对象,形成聚集或组合关联结构,这个部分对象为多个类共享,而不必在每一个对象类中重复定义。,2024年10月30日,第,76,页,11.3.3,聚合关系设计,聚集和组合的区别如下。,(,1,)聚集关系也称为“,has-a”,关系,组合关系也称为“,contains-a”,关系,(,2,)聚集关系表示事物的整体,/,部分关系的较弱的情况,组合关系表示事物的整体,/,部分关系的较强的情况。,(,3,)在聚集关系中,代表部分事物的对象可以属于多个聚集对象,可以为多个聚集对象所共享,而且可以随时改变它所从属的聚集对象。代表部分事物的对象与代表聚集事物对象的生存期无关,一旦删除它的一个聚集对象,不一定也就随即删除代表部分事物的对象。在组合关系中,代表整体事物的对象负责创建和删除代表部分事物的对象,代表部分事物的对象只属于一个组合对象。一旦删除组合对象,也就随即删除相应的代表部分事物的对象。,在设计类图时,设计人员是根据需求分析描述的上下文来确定是使用聚集关系还是组合关系。对于同一个设计,可能采用聚集关系和采用组合关系都是可以的,不同的只是采用哪,种关系更为合适。,2024年10月30日,第,77,页,2024年10月30日,第,78,页,11.4,面向对象设计优化,按照前述分析和设计规则进行系统分析与设计得到的系统模型,不能保证一定是最优的设计,通常还需要根据系统需求和设计要求做一些优化,本节介绍在面向对象设计阶段中常用的优化策略。,1,确定优先级,系统分析与设计中包含很多不同的质量指标,但这些质量指标并不是同等重要的,设计人员必须确定各项质量指标的相对重要性,即确定优先级,以便在优化设计时制定折中方案。,系统整体质量与选择的折中方案密切相关,设计优化要进行全局考虑,确定各项质量指标的优先级,否则容易导致系统资源的严重浪费。在折中方案中设置的优先级一般是模糊的,最常见的情况是在效率和清晰性之间寻求适当的折中方案。,下面两部分分别讲述在优化设计时提高效率的技术和建立良好继承结构的方法。,11.4,面向对象设计优化,2,提高效率的几项技术,(,1,)增加冗余关联以提高访问效率,在面向对象分析过程中,应该避免在对象模型中存在冗余关联,以避免冗余关联降低模型清晰度。但在面向对象设计过程中,在考虑用户访问模式及不同类型访问彼此间的依赖关系时,设计人员会发现,分析阶段确定的关联可能并没有构成效率最高的访问路径,在这种情况下,设计人员需要根据实现的具体要求补充部分冗余关联以提高访问效率。,2024年10月30日,第,79,页,11.4,面向对象设计优化,(,2,)调整查询次序,根据优化要求,改变了对象模型的结构后,还可以通过优化算法进一步优化设计。优化算法的一个途径是尽量缩小查找范围,因此根据具体问题的查询请求,通常需要调整查询次,序以便改进和优化设计。,(,3,)保留派生属性,一般情况下,通过某种计算从其他数据派生出来的数据在模型中是不再保存的,否则就会出现数据冗余,但在某些特殊情况下,为避免重复计算复杂的表达式,可以把派生数据作为派生属性保存起来,在类似的表达式中重用,这也是采用空间来换取时间的一种效果。派生属性既可以定义在原有类中,也可以用对象保存起来并定义在新类中,只是在修改了基本对象时,必然引起所有依赖于它的、保存派生属性的对象的修改。,2024年10月30日,第,80,页,11.4,面向对象设计优化,3,调整继承关系,在面向对象设计过程中,建立良好的继承关系是优化设计的一项重要内容。继承关系能够为一个类族定义一个协议,并能在类之间实现代码共享以减少冗余。一个父类和它的子类被称为一个类继承。利用类继承可以把若干类组织成一个逻辑结构。,2024年10月30日,第,81,页,11.4,面向对象设计优化,在建立类继承过程中,要注意下列问题。,(,1,)抽象与具体,在设计类继承时,一般使用自顶向下或自底向上相结合的方法,设计方法为:, 首先创建一些满足具体用途的类;, 其次对它们进行归纳,归纳出一些通用的类作父类;, 然后根据需要再次派生出具体类;, 最后如果需要再次归纳。,经过上述持续不断的演化过程,设计出具有良好继承关系结构的类族。,2024年10月30日,第,82,页,11.4,面向对象设计优化,(,2,)为提高继承程度而修改类定义,在系统设计过程中,利用继承关系时,有时需要进行类归纳来提高继承程度,如果在一组相似的类中存在公共的属性和行为,就可以把这些公共的属性和行为抽取出来重新定义一个新类,作为这些相似类(即子类)的共同的祖先类,以便供它的子类继承,这个过程称为类归纳。类归纳时,要注意两点:一是不能违背领域知识和常识;二是应该确保现有类的协议(即同外部世界的接口)不变。,2024年10月30日,第,83,页,11.4,面向对象设计优化,(,3,)利用委托实现行为共享,一般地,只有当子类确实是父类的一种特殊形式时,利用继承机制实现共享才是合理的,但很多时候,程序员只是想利用继承作为实现操作共享的一种手段,并不打算确保子类和父类具有相同的行为,这时,如果从父类继承的操作中包含了子类不应有的行为,则可能引起麻烦。,如果程序员只想用继承作为实现操作共享的一种手段,则利用委托(把一类对象作为另一类对象属性,在两类对象间建立组合关系)也可以达到同样的目的,而且这种方法更安全。使用委托机制时,只有有意义的操作才会委托另一类对象实现,因此,不会发生不慎继承了无意义甚至有害操作的问题。,2024年10月30日,第,84,页,2024年10月30日,第,85,页,11.5,面向对象系统的实现,所谓面向对象实现,主要包括下述两项工作:一是把面向对象设计结果翻译成用某种程序设计语言书写的面向对象程序;二是测试并调试面向对象程序。,面向对象程序的质量基本上由面向对象设计的质量决定,但是所采用的编程语言的特点和程序设
展开阅读全文