《面向对象设计》PPT课件.ppt
第10章 面向对象设计,10.1 面向对象的设计准则 10.2 问题域子系统设计 10.3 人机交互子系统设计 10.4 任务管理子系统设计 10.5 数据管理子系统设计 10.6 服务与关联的设计 10.7 面向对象设计的优化,10.1 面向对象的设计准则,10.1.1 设计准则 1.模块化 模块化是软件设计的重要准则。在面向对象开发方法中,将对象定义为模块。对象把数据结构和作用在数据上的操作封装起来构成模块。对象是组成系统的基本模块。,2.抽象 类是一种抽象数据类型,在该数据类型之上,可以创建对象(类的成员)。类包含相似对象的共同属性和服务,它对外定义了公共接口,构成了类的规格说明(即协议),供外界合法访问。通过这种接口访问类实例中的数据。通常把这类抽象称为规格说明抽象。3.信息隐藏 在面向对象方法中,对象是属性和服务的封装体,这就实现了信息隐藏。类结构分离了接口与实现,类的属性的表示方法和操作的实现算法,对于类的用户来说,都应该是隐藏的,用户只能通过公共接口访问类中的属性。,4.弱耦合 所谓耦合,是指一个软件结构内不同模块之间互连的依赖关系。依赖关系越多耦合度越强,依赖关系越少耦合度越弱。在面向对象方法中,对象是最基本的模块,不同对象之间相互关联的依赖关系表示了耦合度。衡量设计优良的一个重要标准就是弱耦合,弱耦合的设计中某个对象的改变不会或很少影响到其他对象。这样给理解、测试或修改带来很大的方便。反之,强耦合会给理解、测试或修改带来很大的难度,并且还降低了该类的可重用性和可移植性。不同对象之间耦合是不可避免的。两个对象必须相互联系相互依赖时,应该通过类的协议(即公共接口)实现两个对象相互依赖(耦合),而不是通过类的具体实现细节来描述。,5.强内聚 所谓内聚,是一个模块内各个元素彼此结合的紧密程度。结合得越紧密内聚越强,结合得越不紧密内聚越弱。强内聚也是衡量设计优良的一个重要标准。在面向对象设计中,内聚可分为下述三类:(1)服务内聚。一个服务应该是单一的,即只完成一个任务。(2)类内聚。类内聚要求类的属性和服务应该是高内聚的,而且它们应该是系统任务所必需的。一个类应该只有一个功能,如果某个类有多个功能,通常应该把它分解成多个专用的类。,(3)一般-特殊内聚。一般-特殊内聚表示:一般-特殊结构符合领域知识的表示形式,也就是说,特殊类应该尽量地继承一般类的属性和服务。这样的一般-特殊结构是高内聚的。例如,虽然表面看来飞机与汽车有相似的地方(都用发动机驱动,都有轮子,),但是,如果把飞机和汽车都作为“机动车”类的子类,则不符合领域知识的表示形式,这样的一般-特殊结构是低内聚的。高内聚的一般-特殊结构应该是,设置一个抽象类“交通工具”,把飞机和机动车作为交通工具类的子类,而汽车又是机动车类的子类。,6.可重用 在面向对象设计中,一个类的设计应该具有通用性,为开发相似的系统提供软件重用可能。软件重用可以提高软件开发生产率,确保目标系统质量。可重用是面向对象开发方法的一个重要特性,也就是说,用面向对象的概念和方法比较容易实现重用。因此,在软件开发过程中,为了实现重用,既要尽量重用已有的类,又要创建可重用的新类。,10.1.2 设计策略 在使用面向对象方法学开发软件的实践中,得出了下面一些基于经验的启发规则,这些规则往往能帮助软件开发人员设计出好的方案来,以保证软件的质量。1.设计结果应该清晰易懂 良好的设计结果应该是清晰易懂的,它能提高软件的可维护性和可重用性。如果一个设计结构不清楚,并且难以理解,是不会被人们接受的。设计时采用以下几个策略能使结果清晰易懂。(1)命名一致。命名应该与专业领域中的名字一致,并且要是符合人们习惯的名字。不同类中相似服务的名字应该相同。,(2)重用协议(公共接口)。在设计中应该使用已经建立了类的协议,避免重复劳动或重复定义带来的差异(不统一)。这些协议可能是其他设计人员已经建立了类的协议,或是在类库中已有的协议。(3)减少消息连接。尽量采用已有标准的消息连接,去掉不必要的消息连接。采用统一模式建立自己需要的消息连接,以便理解和使用,增强可理解性和可使用性。(4)避免模糊的定义。应该定义具有明确、有限用途的类,避免那些模糊的、不准确的类定义。,2.一般-特殊结构的深度应适当 从基类派生子类,再从子类派生下一层子类,这样的一般-特殊结构的类层次数应该适当,不必过于细化,层次的深度应该是有限的。一般来说,在一个中等规模(大约包含100个类)的系统中,类层次数应保持为72。,3.设计简单的类 类设计应该尽量小而简单,便于开发和管理。定义很大的类,它所包含的属性和服务相对就多,会给开发和使用带来困难。实践表明,简单类一个类的定义在50行左右(或两屏)。简单类可按照下列的策略定义。(1)避免包含太多的属性。一个类包含的属性多少将决定类的复杂程度。一个类包含太多的属性表明该类过于复杂了,因此,就可能有过多的作用在这些属性上的服务。(2)避免提供太多服务。一个类包含的服务多少也是决定类的复杂程度的一个重要因素。太复杂的类所提供的服务肯定太多。一般来说,一个类提供的公共服务不要超过七个。,(3)明确精练的定义。如果一个类的任务简单了,则它的定义就明确精练了,通常任务简单的类可用几个简单语句描述。(4)简化对象间的通信。每个对象应该独立完成任务。也就是说,对象在完成任务时,尽量不要依赖于其他对象的配合(帮助),对象之间过多的依赖会破坏类的简明性和清晰性。虽然,遵循上述设计策略能设计出明确精练的较小的类,但在开发大型软件系统中,必定会有大量较小的类设计出来,这将会导致类间的通信变复杂。采用划分“主题”的方法,可以解决这个问题。,4.设计简单的协议 消息中的参数越多表示对象之间传递的消息越复杂,同样表明对象之间的依赖关系越复杂,即对象间的耦合度越高。一般来说,简单消息中的参数不要超过三个。过多的参数会导致对象的修改较复杂,因为对一个对象的修改往往导致其他对象的修改。,5.设计简单的服务 类中的服务应该设计得既简单又小,用35行源程序代码比较适合。服务的源程序中不要包含过多的语句行,或者复杂的语句控制结构,如分支嵌套、循环嵌套和函数调用等。如果一个服务非常复杂,则应该检查该服务的控制结构,并进行分解和简化,尽量避免设计复杂的服务。,6.减少设计变动 随着设计方案逐渐成熟,改动也应该越来越小,这样才能设计出优良的结果。优良的设计能保证软件质量,并能提高软件的可重用性。因此,在设计中尽可能少改动,或者尽可能缩小修改的范围。,10.1.3 系统分解与组织 面向对象设计同过程设计一样,自顶向下进行功能分解。在设计比较复杂的应用系统时,将系统分解成若干个比较小的部分,再分别设计每个部分。这样既简化了应用系统,又降低了设计的难度,并有利于实现和维护。,系统是根据功能来分解的,我们将系统分解的各个部分(即系统的主要组成部分)称为子系统。例如,编译系统可划分成词法分析、语法分析、中间代码生成、优化、目标代码生成和出错处理等子系统。子系统不是单一的对象或功能,而是面向对象分析模型的五个层次的集合。子系统的划分不能太多,要与系统规模相匹配,最底层的子系统成为模块。子系统间交互的形式和交互的信息由接口确定,因此,接口应该简单、明确,以便设计出相对独立的子系统,减少子系统的依赖性。,1.面向对象设计的五个层次、四个部分 面向对象设计是在面向对象分析模型的基础上建立对象模型的过程。两个阶段同样是建立对象模型,只是面向对象分析建立了问题域的对象模型,而面向对象设计建立的是求解域的对象模型。因此,面向对象设计模型同样由主题、类-对象、结构、属性和服务等五个层次组成,并且又扩充了问题域(PDC)、人机交互(HIC)、任务管理(TMC)和数据管理(DMC)四个部分。,这五个层次就像五个透明的图层,而整个模型像是由五个图层(水平切片)合并而成的,五个层次一层比一层描述得更具体、更明确;四大组成部分又可想象成为整个模型的四个垂直切片。不同的应用系统中,这四个子系统的侧重程度和规模都不同,应该根据系统规模的大小确定子系统的数目。在复杂的系统中,子系统可能要继续分解;对于小系统来说,可能要合并小的子系统。典型的面向对象设计模型如图10.1所示。,图10.1 典型的面向对象设计模型,2.子系统间的交互方式 在应用系统中,子系统之间的关系可分为客户/服务器关系和同等伙伴关系两种。这两种关系对应两种交互的方式,即客户/服务器交互方式和同等伙伴交互方式。(1)客户/服务器交互方式。客户/服务器交互方式也称单向交互方式。在客户/服务器关系中,作为“客户”的子系统调用作为“服务器”的子系统,执行某些服务后并返回结果。在该交互方式中,任何交互行为都是由客户驱动的,因此,作为客户的子系统必须了解作为服务器的子系统的接口,而服务器不必了解客户的接口。,(2)同等伙伴交互方式。同等伙伴交互方式也称双向交互方式。在该交互方式中,每个子系统都可能调用其他子系统,因此,每个子系统都必须了解其他子系统的接口,子系统间必须相互了解接口。与客户/服务器关系比较,同等伙伴交互关系中子系统之间的交互更复杂,而且这种交互方式还可能构成通信环路,会给设计带来难度,并容易出现设计错误。通常,系统使用客户/服务器关系,因为单向交互更容易理解,也更容易设计和修改,而双向交互相对困难些。,3.系统组织 将子系统组织成完整的系统有两种方式,即水平层次组织和垂直块组织。1)层次组织 层次组织是将子系统按层组织成为一个层次软件系统,每层是一个子系统。上层建立在下层的基础上,下层为上层提供必要的服务。各层内所包含的对象是相互独立的,而不同层次上的对象,相互间有关联。低层子系统提供服务,相当于服务器,上层子系统使用下层提供的服务,相当于客户。这样构成上、下层之间的客户/服务器关系。这种组织方式使软件系统形成层次结构。,层次结构又可分为封闭式和开放式两种。在封闭式结构中,每层子系统只根据相邻下层建立,且仅使用相邻下层提供的服务。这种方式降低了各层次之间的相互依赖性,更容易理解和修改,因为一个层次的接口只影响与其相邻的上一层。在开放式结构中,某层子系统可以使用其下面的任何一层子系统所提供的服务。该方式减少了各层上重新定义的服务的需求,使得整个系统更高效、更紧凑。但是,该方式没有遵守信息隐藏的原则,对任何一个子系统的变更都会影响到更高层次的那些子系统。设计软件系统时应该权衡设计准则的各因素而决定组织系统结构的方式。,通常,在需求陈述中只描述了系统的顶层和底层的内容,顶层就是用户看到的目标系统,底层则是可以使用的资源(如硬件、操作系统、数据库等)。这两层间差异很大,为了减少不同层次之间的概念差异,设计者必须引入一些中间层次来弥补。,2)块组织 块组织将系统垂直地分解成若干个相对独立的、弱耦合的子系统,一个子系统相当于一块,每块提供一种类型的服务。在一个系统中,可利用层次和块的混合组织方式。各种可能的组合结构,可以成功地把多个子系统组成一个完整的、混合结构的软件系统。在混合结构组织中,同一层次可以由若干块组成,而同一块也可以分为若干层。大多数复杂系统组织采用层次与块的混合结构。例如,图10.2表示一个典型应用系统的组织结构。,图10.2 典型应用系统的组织结构,4.设计系统的拓扑结构 构成完整系统的拓扑结构有:管道型、树型、星型等。为了减少子系统之间的交互次数,设计时应该采用与问题结构相适应的、尽可能简单的拓扑结构。,10.2 问题域子系统设计,问题域子系统也称问题域部分(PDC,Problem Domain Component)。面向对象分析到面向对象设计是一个平滑的过渡,即没有间断没有明确的分界线。面向对象分析建立系统的问题域对象模型,而面向对象设计是建立求解域的对象模型。都是建模,但两者必定性质不同,分析建模可以与系统的具体实现无关,设计建模则要考虑系统的具体实现环境的约束,如要考虑系统准备使用的编程语言,可用的软构件库(主要是类库)以及程序员的编程经验等约束问题。,面向对象方法中的一个主要目标是保持问题域组织框架的完整性、稳定性,这样可提高分析、设计到实现的追踪性。因为系统的总体框架都是建立在问题域基础上的,所以,在设计与实现过程中无论做怎样的修改,例如增加具体类、属性或服务等,都不会影响开发结果的稳定性。稳定性是在类似系统中实现重用分析、设计和编程结果的关键因素。为更好地支持系统的扩充,也同样需要稳定性。,问题域子系统可以直接引用面向对象分析所得出的问题域精确对象模型,该模型提供了完整的框架,面向对象设计就应该保持该框架结构。面向对象设计在分析模型的基础上,从实现角度对问题域模型作一些补充或修改,修改包括增添、合并或分解类-对象、属性及服务,调整继承关系等。如果问题域子系统相当复杂庞大时,则应把它进一步分解成若干个更小的子系统。下面讲述在面向对象设计过程中,对问题域对象模型作的增补或修改的方法。,1.调整需求 当用户需求或外部环境发生了变化,或者分析员对问题域理解不透彻或缺乏领域专家帮助,以致建立了不能完整、准确地反映用户真实需求的面向对象分析模型时,需要对面向对象分析所确定的系统需求进行修改。一般来说,首先对面向对象分析模型作简单的修改,然后再将修改后的模型引用到问题域子系统中。,2.重用现有的类 设计时应该在面向对象分析结果的基础上实现现有类的重用,现有类是指面向对象程序设计语言所提供的类库中的类。因此,在设计阶段就要开始考虑重用,为代码重用奠定基础。如果确实需要创建新的类时,则在设计新类时,必须考虑它的可重用性。,下面介绍重用已有的类的过程。(1)选择类库中可重用的现有类,加入到问题域子系统中,并标出现有类中对本系统无用的属性和服务,以致将无用的属性和服务降到最低程度。(2)将问题域类中从现有类继承来的属性和服务标出来,它们再没有必要定义在问题域类内了。(3)确定被重用的现有类和问题域类之间的一般-特殊关系,也就是说,以重用现有类为基类,派生出问题域类。(4)修改问题域类相关的关联,必要时用与重用现有类相关的关联替换与问题域类相关的关联。,3.组合问题域类 通常,为了把问题域类组合在一个类库中,需要引入一个根类(抽象类)将问题域类作为从属类组织在一起。当没有更先进的、更好的组合机制时,才采用该种组合方法。另外,可通过建立协议来完成这种组织。,4.增添一般化类以便建立协议 在设计过程中,经常发现许多具体类需要有一个相似的协议,即它们都需要定义一组相似的服务。这时可以引入一个附加的根类,以便建立这个协议。也就是说,定义公共服务集合,在特殊类中详细定义这些服务。,5.简化继承 当面向对象模型中的一般-特殊结构包括多继承,而使用一种只有单继承和无继承的编程语言时,需要对面向对象模型作一些修改,即将多继承化为单继承,单继承化为无继承,用单继承和无继承编程语言来表达多继承功能。,6.实例设计 在面向对象设计过程中,ATM系统的问题域子系统的结构如图10.3所示。把ATM系统的问题域子系统,进一步分解成更小的ATM站子系统,中央计算机子系统和分行计算机子系统,构成星型拓扑结构。以中央计算机为中心向外连接(用专用电话线),与所有ATM站和分行计算机通信。区分每个ATM站和每台分行计算机连向中央计算机的电话线,分别用ATM站号和分行代码来实现。这里假设面向对象分析模型是完整的,在面向对象设计过程中对问题域模型不必作实质性的修改或扩充了。,图10.3 ATM系统问题域子系统的结构,10.3 人机交互子系统设计,人机交互子系统也称人机交互部分(HIC,Human Interaction Component)。人机交互部分的设计结果,将对用户使用系统带来很大影响。人机界面设计得好,则会使系统产生魅力,吸引用户经常使用系统,并觉得与系统的交互是友好的、兴奋的,还能提高工作效率;反之不然。为了得到良好的人机界面,在分析阶段要对用户进行分析,在设计阶段要延续该分析,包括对用户、交互时间、交互技术等进行分析。,在人机交互子系统设计中,在初步分析用户界面需求的基础上,对人机交互的细节进行详细设计,包括对窗口、对话框和报表的形式,设计命令层次组织等内容的设计。设计人机交互子系统的关键,是使用原型技术。建立人机界面的原型,征求用户的意见,获取用户的评价,也是设计人机界面的一种有效途径。,1.设计人机交互界面的准则 要把人机交互界面设计得友好,让用户满意,应该遵循下列准则:(1)一致性。在人机交互界面中,术语、步骤、动作的使用都要一致。(2)减少步骤。人机交互界面设计时,应尽量减少为完成某个操作而敲击键盘、点击鼠标、点击下拉菜单的次数,并且适应不同技术水平的用户,还得有极小的响应时间,特别应该为熟练用户提供简捷的操作方法(例如热键)。,(3)及时提供反馈信息。在运行时间较长时,应该有提示使得用户不感到寂寞。每当要用户等待系统完成一个活动时,系统都应该向用户提供有意义的、及时的反馈信息,以便能够让用户知道系统当前已经完成该活动的进度如何,是否正常等信息,不要“哑播放”。(4)提供撤消命令。人与系统交互时难免会出错误,系统应该提供“撤消(Undo)”命令,以便用户发现错误时能及时撤消错误操作,进行补救处理。,(5)减少记忆。好的界面不需要用户记忆使用步骤,操作比较简单。(6)易学易用。界面应该易学易用,应该有联机学习、操作手册以及其他参考资料,以便用户在需要时可随时参阅。(7)富有吸引力。给用户设计友好的、趣味的、具有吸引力的人机交互界面,从而吸引用户使用。,2.设计人机交互子系统的策略 1)分类用户 人机交互界面的两个要点是人如何命令系统及系统如何向用户提交信息。因此,设计好人机交互界面的首要任务是认真研究使用系统的用户,深入到用户的工作现场,仔细观察用户的工作流程。观察用户必须完成哪些工作,如何工作的,思考完成这些工作在系统中应该提供哪些工具以及如何实现,如何使工具使用起来更方便、更有效。为了设计出符合用户需要的界面,应该深入了解用户的需要与爱好,可将用户按照不同角度进行分类。,按技能分类(初级中级高级)。按职务分类(总经理部门经理职员)。按工作性质分类(行政人员技术人员)。按专业知识分类(外专业/专业/系统员/程序员)。,2)描述用户及其任务脚本 对以上定义的每类用户的情况,就下述问题进行考虑并制表,如表10.1所示。,表10.1 描述用户及其任务的脚本内容,3)设计命令层 设计命令层是界面设计的重要部分,一般包含下列工作。(1)研究现有的人机交互的准则。命令层设计有许多方式,但目前最受用户喜爱的是Windows界面,Windows已经成了微机上图形用户界面事实上的工业标准。所有Windows应用程序的界面是一致的,窗口布局、菜单、术语等使用,以及界面的风格、习惯等都是一致的,Windows的命令层设计采用了下拉式菜单和弹出式菜单,而且各菜单的组织方式也类似。设计图形用户界面时,应该保持与普通Windows应用程序界面一致,并遵守广大用户习惯的约定,这样才会被用户接受和喜爱。,(2)设计初始命令层。所谓命令层,是将系统中的可用服务用过程抽象机制组织起来的一种体现。设计时首先从服务的基本过程抽象开始,确定系统中最上层(如大的操作,相近小命令的总称,多层命令的最上层等),然后再修改它们,以符合目标系统的特定需要。,(3)优化命令层。为使命令层完善、合理以及使用方便,应该考虑下列一些因素,作进一步修改。排列:检查每个服务的名字,并将服务排在命令层中的合适位置。可按系统功能(服务)顺序排列,也可以按用户习惯的工作顺序排序。整体-部分组合:通过服务本身发现整体-部分关系,来帮助在命令层中对服务组织和分组。,宽度和深度:通常,命令层中同一层显示命令的个数(宽度),设计为(72)个比较合适;命令层中层数(深度)设计为3层比较合适。这样符合人的短期记忆能力。减少操作步骤:做同样的工作,按键或拖动鼠标越少越好。并为高级用户提供简捷的操作方法。,4)设计人机交互类 人机交互类设计,可在操作系统及编程语言的基础上,利用类库中现有的、适用的类来派生出符合目标系统需要的类,作为人机交互类。,10.4 任务管理子系统设计,1.分析并发性 不仅在系统软件中有并发行为,而且在应用软件中也有并发行为,因此,实现中存在并发行为。在程序的执行时间上与其他程序有交叠的现象,这种时间交叠现象称为“并发性”。因此,任务管理子系统在设计时,应找出并分析系统中任务的并发性。,分析并发性的主要依据是系统的动态模型。如果对象间不存在交互,或者说它们能同时接收事件,那么这两个对象是并发的。通过检查各个对象的状态图及它们之间交换的事件,把若干个非并发的对象归并到一起。独立的任务把必须并发进行的行为分离开来。这种并发行为既可以在不同的处理器上实现,也可以在单个处理器上利用多任务操作系统仿真实现。一般来说,划分任务,是为了简化系统中必须的并发行为的设计和编码。,2.设计任务管理子系统 1)确定事件驱动任务 由某个事件触发而引起的任务称事件驱动任务。事件通常表明一个设备传输过来的一个信息,事件是由设备引起的。任务是对事件的处理。一个任务可以设计成由一个事件来触发(驱动),该事件常常是对一些数据的到达发信号,而这些数据可能来自输入数据行,或者另一个任务写入的数据缓冲区。这类任务可能主要完成通信工作,例如,与设备、屏幕窗口、其他任务、子系统、另一个处理器或其他系统通信。,事件驱动任务的工作过程为:任务处于睡眠状态(不消耗处理器时间),等待来自数据行或其他数据源的中断;接收到中断就唤醒了该任务;阅读数据并把数据放入内存缓冲区或其他目的地;向需要知道此事件的对象发出通知,然后该任务又回到睡眠状态。,2)确定时钟驱动任务 按特定的时间间隔被触发后执行某些处理的任务称时钟驱动任务。例如,某些设备需要周期性地获得数据;某些人机接口、子系统、任务、处理器或其他系统也可能需要周期性地通信。时钟驱动型任务的工作过程为:任务设置了唤醒时间后进入睡眠状态;等待来自系统的中断;接收到中断,任务被唤醒;进行处理,通知有关的对象;该任务又回到睡眠状态。,3)确定优先任务 根据事件的优先级高低来做处理的任务称优先级任务。它可以满足高优先级或低优先级的处理需求。(1)高优先级:有些服务可能是高优先级的,需要把这类服务划分成独立的任务,使该类服务在一个严格限定的时间内完成。(2)低优先级:有些服务是低优先级的,属于低优先级处理(通常指那些后台处理)。设计时可能用附加的任务把这种服务分离出来。任务的划分是根据时间决定优先级,根据优先级的高低划分出轻重缓急的任务。,4)确定关键任务 设计时应该分离出那些对于系统的成败特别关键的任务,该类任务通常都有严格的可靠性、安全性要求。设计时可用附加的任务来分离出关键的任务,应该进行深入细致的设计、编码和测试,以满足高可靠性、安全性处理的要求。也就是说,根据需求决定任务的主次,保证关键任务。,5)确定协调任务 当系统中有三个以上任务时,就应该考虑增加一个任务,用来协调任务之间的关系,该任务称为协调任务。从一个任务到另一个任务的转换时间叫现场转换时间。协调任务用来控制现场转换时间时,将会给系统设计带来困难,但是引入协调任务可为封装不同任务之间的协调控制带来好处。该任务的行为可用状态转换矩阵来描述。这样的任务应该只做协调工作,不必分配它其他的工作。,6)审查每个任务 对任务的性质进行审查,去掉人为的、不必要的任务,要使任务数保持到最少。设计多任务系统的主要问题是,设计者常常为了自己设计和编程的方便而增加任务。这样既增加了总体设计的技术复杂度,又降低了系统的可理解性,从而也加大了系统维护的难度。,7)定义每个任务 任务定义包括以下内容:(1)任务的内容。首先给任务命名,然后简要地描述任务。如果一个任务可以分解成多个任务,则修改该服务的名称以及描述,使每个服务映射到一个任务。(2)如何协调。定义每个任务怎样协调工作。指出它是任务事件驱动的还是时钟驱动的。对于事件驱动的任务,描述触发该任务的事件;对时钟驱动的任务,描述在触发之前所经过的时间间隔,同时指出是一次性的还是重复的时间间隔。,(3)如何通信。定义每个任务如何通信。指出任务从哪里取得数据值,往哪里送数据。任务定义模板如下:Task Name Task DescriptionTask ProridyTask Services includedCoordinates By Communicates ByEndTask,10.5 数据管理子系统设计,数据管理子系统也称数据管理部分(DMC,Data Management Component)。数据管理子系统为面向对象设计模型提供了在特定的数据管理系统之上,存储或检索对象的基本结构。设计数据管理子系统的目的是,将目标软件系统中依赖开发平台的数据存取部分与其他功能分离,数据存取通过一般的数据存储管理模式(文件、关系数据库或面向对象数据库)实现,但实现细节集中在数据管理子系统中。这样既有利于软件的扩充、移植和维护,又简化了软件设计、编码和测试的过程。,10.5.1 选择数据存储管理模式 选择数据存储管理模式是数据管理子系统设计的首要任务。可供选择的数据存储管理模式有三种:文件管理系统、关系数据库系统和面向对象管理系统。设计者应该根据应用系统的特点,选择一种合适的数据存储管理模式。1.文件管理系统 文件管理系统提供了基本的文件处理和分类能力。它的特点是长期保存数据,成本低而且简单。但文件操作繁琐,实现比较困难,必须编写大量的代码。此外,文件管理系统是操作系统的一个组成部分,不同操作系统的文件管理系统往往有明显的差异。,2.关系数据库管理系统 关系数据库管理系统建立在关系理论基础上。它用若干个表来管理数据,表中的每一行表示表中的一组值,每一列有一个单一的(原子)值在其中。它具有以下优点:(1)提供了各种最基本的数据管理功能。例如,中断恢复、多用户共享、多应用共享、完整性和事务支持等。(2)为多种应用提供了一致的接口。(3)支持标准化的SQL语言。,关系数据库管理系统为了做到通用和一致性,实现相当复杂且存在一定不足,以致限制了它的普遍使用。缺点如下:(1)运行开销大。即使只完成简单的事务(例如,只修改表中的一行)也需要较长的时间。(2)不能满足高级应用的需求。关系数据库管理系统是为商务应用服务的,商务应用中数据量虽大,但数据结构却比较简单。一般来说,在数据类型丰富或操作不标准的应用中,很难用关系数据库管理系统实现。(3)与程序设计语言的连接不自然。大多数程序设计语言本质上是过程性的,每次只能处理一个记录。而SQL语言支持面向集合的操作,是一种非过程性语言,两者之间存在差异,连接不方便。,3.面向对象数据库管理系统 面向对象数据库管理系统(OODB,Object Oriented Data Base)是一种新技术,它扩展设计途径如下:(1)在关系数据库的基础上,加强了一些操作功能。例如,增加了抽象数据类型和继承性,以及创建及管理类和对象的通用服务。这种OODB称为扩充的关系数据库管理系统。(2)面向对象程序设计语言中扩充了数据库的功能。例如,扩充了存储和管理对象的语法和功能。这种OODB称为扩充的面向对象程序设计语言。,(3)从面向对象方法本身出发来设计数据库。开发人员可以用统一的面向对象观点进行设计,不再需要区分存储数据结构和程序数据结构。首先保留对象值,然后在需要时创建该对象的一个副本。这是大多数对象数据管理模式都采用的“复制对象”的方法。扩展的面向对象程序设计语言则支持了“永久对象”方法:确切地存储同样的对象,包括对象的内部标识,而不是仅仅存储一个对象的副本。使用这种方法,当一个对象从存储库检索到时,它与先前存在的那个对象是完全相同的。“永久对象”方法,为在多用户环境下从对象服务器中共享对象奠定了基础。,10.5.2 设计数据管理子系统 无论基于哪种数据管理模式,设计数据管理子系统都包括设计数据格式和设计相应的服务两部分。1.设计数据格式 不同的数据存储管理模式,其设计数据格式的方法也不同。下面分别介绍每种数据存储管理模式的数据格式设计方法。,1)文件系统 文件系统设计数据格式的步骤包括:(1)列表给出每个类的属性(既包括类本身的定义属性又包括继承下来的类属性);(2)将所有属性表格规范为第一范式;(3)为每个类定义一个文件;(4)测量性能和需要的存储容量能否满足实际性能要求;,(5)若文件太多时,则把一般-特殊结构的对象文件合并成一个文件,以减少文件数量。必要时把某些属性组合起来,并用某种编码值表示这些属性,而不再分别使用独立的域表示每个属性。这样做可以减少所需要的存储空间,但是增加了处理时间。,2)关系数据库管理系统 关系数据库管理系统设计数据格式的步骤为:(1)列出每个类的属性表;(2)将所有属性表格规范为第三范式;(3)为每个类定义一个数据库表。(4)测量性能和需要的存储容量能否满足实际性能要求;(5)若不满足再返回第二步设计规范,修改原来设计的第三范式,以满足性能和存储需求。,3)面向对象数据库管理系统 面向对象数据库管理系统设计数据格式的步骤为:(1)对于在关系数据库上扩充的面向对象数据库管理系统,其处理步骤与基于关系数据库的处理步骤类似。(2)对于由面向对象程序设计语言扩充而来的面向对象数据库管理系统,则不需要对属性进行规范化,因为数据库管理系统本身具有把对象值映射成存储值的功能。,2.设计相应的服务 如果某个类的对象需要存储起来,则在该类中应该增加一个属性和服务,用于完成存储对象自身的操作。通常把增加的属性和服务与对象中其他的属性和服务分离,作为“隐含”的属性和服务,在类-对象的定义中描述,不在面向对象设计模型的属性和服务层中显式地表示出来。“存储自己”的属性和服务形成了问题域子系统与数据管理子系统之间必要的桥梁。若系统支持多继承,那么用于“存储自己”的属性和服务应该专门定义在一个基类“Object Server(对象服务器)”中,通过继承关系使那些需要存储对象的类从基类中获得该属性和服务。,同设计数据格式一样,不同的数据存储管理模式,其设计相应的服务的方法也不同。下面分别介绍每种数据存储管理模式的相应服务的设计方法。1)文件系统 采用文件系统设计时,对象需要确定打开哪个文件,在文件中如何定位,如何检索出旧值(如果存在)以及如何更新值。因此,需要定义一个“Object Server类”,该类应该提供两个服务:(1)告知对象如何存储自身;(2)检索已存储的对象(查找、取值、创建或初始化对象),以便把这些对象提供给其他子系统使用。,2)关系数据库管理系统 采用关系数据库管理系统设计时,对象需确定访问哪些数据库表,如何检索到所需要的行(元组),如何检索出旧值(如果存在)以及如何更新值。因此,还应该专门定义一个“Object Server”类,并声明它的对象。该类应提供下列服务:(1)告知对象如何存储自身;(2)检索已存储的对象(查找,取值,创建或初始化对象),以便由其他子系统使用这些对象。,3)面向对象数据库管理系统(1)对于在关系数据库上扩充的面向对象数据库管理系统,与使用关系数据库管理系统时方法相同。(2)对于由面向对象程序设计语言扩充而来的面向对象数据库管理系统,没有必要定义专门的类,因该系统已经提供了为每个对象“存储自己”的行为。只需给需要长期保存的对象加个标记,这类对象的存储和恢复由面向对象数据库管理系统负责完成。,3.实例设计 用图10.3所示的ATM系统为例,具体说明数据管理子系统的设计方法。假设采用关系数据库管理系统存储数据。从系统可知,在分行计算机中存放的是惟一的永久性数据。因为有多个并发事务同时访问这些数据,而且必须保持数据的一致性和完整性。因此,应该把每个事务作为一个不可分割的批操作来处理,由事务封锁账户直到该事务结束为止。需要存储的对象在该例中主要是账户类的对象。为了支持数据管理子系统的实现,账户类对象必须知道自己是怎样存储的,下面介绍两种方法可完成这个任务。,须知道自己是怎样存储的,下面介绍两种方法可完成这个任务。(1)由每个对象自身存储。账户类对象在接到“存储自己”的消息后,需要增加一个属性和一个服务来定义存储自己的行为,以便知道怎样把自身存储起来。(2)由数据管理子系统负责存储对象。账户类对象在接到“存储自己”的消息后,知道应该发送什么消息到数据管理子系统,以便把它的状态由数据管理子系统保存起来,因此也需要增加属性和服务来定义这些行为。使用这种方法的优点是没有必要修改问题域子系统。,应该定义一个数据管理类Object Server,并声明它的对象。这个类提供下列服务:通知对象保存自身或保存需长期存储的对象的状态;检索已存储的对象并可使其存储和恢复。,10.6 服务与关联的设计,10.6.1 设计服务 设计类中的服务是面向对象设计的一项重要内容。因为面向对象分析建立起来的对象模型通常并没有详细描述类中的服务,而面向对象设计则是扩充、完善和细化面向对象分析模型的过程,所以,详细描述类中的服务是面向对象设计的必要任务。,1.确定类中应有的服务 要正确确定类中应有的服务,必须综合考虑对象模型、动态模型和功能模型。对象模型是进行对象设计的基本依据,但是,在面向对象分析的对象模型的类中,没有列出服务或只列出少量的几个最基本的服务。面向对象设计过程中,必须把动态模型中对象的行为和功能模型中的数据处理转换成服务,加入到对象的类中,而这些服务必须由合适的类所提供。1)从对象模型中引入服务 对象模型描述了系统的对象、属性和服务,则可将这些对象(以及对象的服务)直接引入到设计中,只是要详细定义这些服务。,2)从动态模型中确定服务 动态模型是由若干个状态图组成,对象的生命周期由一张状态图描绘,执行对象服务使得状态转换,状态转换是指对象状态的变化。对象接收到事件后驱动对象的执行服务,实际上,事件可用消息表现,对象接收消息由该消息的操作符指定服务,该服务改变对象状态,即修改相应的属性值,并完成对象应做的动作。对象的动作不但与事件有关,而且与对象的状态有关。因此,服务的算法必定与对象的状态有关。如果一个对象在不同状态下接收同样事件,则对象的行为可不同。由此可用一个依赖于状态的多分支控制结构来实现服务的算法。,动态模型描述了系统是如何响应外部事件的,程序的主要控制结构来自于动态模型。设计程序的控制结构,有时可通过内部的调度机制识别事件,并将事件映射成操作调用来显式地实现程序控制;有时可通过选择的算法按动态模型中确定的顺序执行操作,来隐式地实现程序控制。,3)从功能模型中确定服务 功能模型由一组数据流图组成,功能模型指明了系统必须提供的服务。数据流图中的某些处理可能对应于某个(些)对象提供的服务,因此,确定操作的目标对象,然后在该对象所属的类中定义这些服务。定义对象所属的类中的服务时,必须为服务选择合适的算法,有了优秀的算法才能设计出快速高效的服务来。此外,如果某个服务特别复杂而很难实现,则可将复杂的服务分解成简单的服务,这样实现起来比较容易(当然分解的理由不仅仅考虑容易实现的因素)。算法和分解是实现优化的重要手段。,2.设计实现服务的方法 上面讨论了如何确定对象所属的类的服务,下面来讨论如何设计实现服务的方法,设计实现服务按下列步骤进行。(1)选择算法:设计实现服务的算法时,选择算法应该考虑的因素如下:算法复杂度:选择算法时,首先是满足用户需求,其次才是追求高效率。根据服务需求选用复杂度较低(即效率较高)的算法。,易理解与易实现:设计时考虑算法的易理解性和易实现性,一个易理解和易实现的算法可能与它的高效率是一对矛盾,设计者应该权衡利弊,考虑各个因素,选择适当的算法。易修改:设计时除了考虑算法的易理解性和易实现性,还应该考虑算法的易修改性。因此,算法设计应该尽可能通用,结构清晰,并能预测到后续可能的修改情况。,(2)选择数据结构:在面向对象分析过程中,仅考虑了系统中数据的静态的逻辑结构,而在面向对象设计过程中,则涉及到选择算法使用的物理数据结构,采用该种数据结构能够正确地、高效地实现算法。多数面向对象程序设计语言都提供了基本数据结构,可供用户自选组合定义。(3)定义内部类和内部操作:在算法设计时,为了提高效率而增加一些类,用来