第6章面向对象的软件设计本章学习内容:1.理解面向对象软件设计的基本原理2.掌握系统设计的过程与方法3.掌握详细设计的内容与过程4.了解面向对象的实现技术5.了解面向对象测试的概念与方法第6章面向对象的软件设计6.1面向对象软件设计概述6.1.1面向对象设计准则1.模块化2.抽象3.信息隐蔽4.低耦合5.高内聚6.可重用第6章面向对象的软件设计6.1.2面向对象设计的过程1.系统设计(1)首先进行系统架构设计,使系统具有良好的稳定性、开放性和可扩充性(2)如果系统复杂,应将系统划分为若干个子系统(3)给系统分配处理机和任务(4)根据数据结构、文件和数据库选择实现数据存储的基本策略(5)标识全局资源和确定控制访问这些资源的机制(6)选择实现软件控制方法(7)考虑边界条件(8)建立折衷的优先权第6章面向对象的软件设计2.详细设计(1)细化、补充类的属性和操作(2)设计类操作的实现算法(3)优化数据访问路径(4)实现外部交互式的控制(5)调整类结构,增加继承性(6)设计类之间的关联的实现方式(7)确定对象属性的精确表示(8)把类和关联打包归纳到模块中第6章面向对象的软件设计6.2系统设计6.2.1逻辑体系架构设计1.层次模式分析(1)分层模式表示层:图形用户界面、窗口等。应用逻辑层:管理业务过程的任务和规则。对象存储层:持久化存储机制,例如,文件系统、数据库等。第6章面向对象的软件设计(2)设计要求层与层之间的耦合应尽可能地松散;级别相同、职责类似的元素应该被组织到同一层中;复杂的模块应被继续分解为粒度更细的层或子系统;应尽量将可能发生变化的元素封装到一层中;每一层应当只调用下一层提供的功能服务,而不能跨层调用;一层绝不能使用上一层提供的功能服务,即不能在层与层之间造成双向依赖。第6章面向对象的软件设计(3)避免循环依赖AlayerA1layerB1layerClayerBlayerAlayerA'layerClayerBlayer第6章面向对象的软件设计2.子系统划分设计准则:子系统应具有良好的接口,通过接口和系统的其他部分通信;除了少数的“通信类”外,子系统中的类应只和该子系统中的其他类协作;子系统的数量不宜太多;可以在子系统内部再次划分,以降低复杂度。第6章面向对象的软件设计6.2.2物理体系结构建模用构件图和部署图来描述系统的物理体系结构1.构件图构件图就是描述构件类及其它们之间的关系。(1)构件间的依赖关系:主要是依赖关系,用来表示一个构件需要另一些构件才能有完整的定义。(2)接口:是一个构件提供给其他构件的一组操作第6章面向对象的软件设计例:第6章面向对象的软件设计2.部署图部署图描述了处理器、设备和软件构件运行时的体系结构。(1)结点:是某种计算资源的物理对象,包括计算机、设备(如打印机、通信设备)等(2)连接:连接用一条直线表示,它指出结点之间存在着某种通信路径,并指出通过哪条通信路径可使这些结点间交换对象或发送消息第6章面向对象的软件设计举例:第6章面向对象的软件设计6.2.3基于构件的建模1.构件的特性独立部署单元可作为第三方的组装单元没有(外部的)可见状态第6章面向对象的软件设计2.设计基于类的构件(1)基本设计原则1)开闭原则:指的是一个模块在扩展性方面应该是开放的,而在更改性方面应该是封闭的。即在设计模块的时候,应该尽量使得模块可以扩展,并且在扩展时不需要对模块的源代码进行修改。第6章面向对象的软件设计2.设计基于类的构件(1)基本设计原则2)Liskov替换原则:指的是子类可以替换父类出现在父类能出现的任何地方。例如,类ClassA要使用ClassB,ClassC是ClassB的子类。如果在运行时,用ClassC代替ClassB,则ClassA仍然可以使用原来ClassB中提供的方法,而不需要做任何改动。第6章面向对象的软件设计3)依赖倒置原则:指的是依赖关系应该是尽量依赖接口(或抽象类),而不是依赖于具体类。在面向对象的设计中,高层的类往往与领域的业务有关,这些类只依赖于一些抽象的类或接口,当具体的实现细节改变时,不会对高层的类产生影响。4)接口分离原则:指的是在设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。即一个类要给多个客户类使用,那么可以为每个客户类创建一个接口,然后这个类实现所有这些接口,而不要只创建一个接口,其中包含了所有客户类需要的方法,然后这个类实现这个接口。第6章面向对象的软件设计(2)构件级设计指导方针1)保持高内聚性。内聚性指构件或类只封装那些相互关系密切,以及与构件或类自身有密切关系的属性和操作。按内聚程度由高到低的排列顺序是:功能内聚、分层内聚、通信内聚、顺序内聚、过程内聚、暂时内聚和实用内聚。2)保持低耦合性。耦合是构件或类之间彼此联系程度的一种定性度量。随着构件或类相互依赖越来越多,构件之间的耦合度亦会增加。按耦合程度由高到低的排列顺序是:内容耦合、控制耦合、印记耦合、数据耦合、例程调用耦合、类型使用耦合、包含或导入耦合、外部耦合。第6章面向对象的软件设计3.实施构件级设计的步骤1)标识出所有与问题域相对应的设计类。2)确定所有与基础设施域相对应的设计类。在分析模型中并没有描述这些类,但此时应对它们进行描述,例如,GUI构件、操作系统构件、对象和数据管理构件等。3)细化所有不能作为复用构件的设计类。详细描述实现类所需要的所有接口、属性和操作。第6章面向对象的软件设计具体包括以下过程:•在类或构件的协作时说明消息的细节•为每个构件确定适当的接口•细化属性并且定义相应的数据类型和数据结构•详细描述每个操作中的处理流第6章面向对象的软件设计4)说明持久数据源(数据库和文件)并确定管理数据源所需要的类5)开发并细化类或构件的行为表示6)细化部署图以提供额外的实现细节7)考虑每一个构件级设计表示,并且时刻考虑其他选择第6章面向对象的软件设计6.3详细设计6.3.1系统详细设计1.细化和重组类2.增加遗漏的属性,指定属性的类型和可见性3.分配职责,定义执行每个职责的方法通用职责分配软件模式:(1)专家模式:应该将职责分配给信息专家(2)创建者模式:如果类A和类B满足下列条件中的一个,就可以把创建B对象的职责分配给A对象。A聚合了B对象;A包含了B对象;第6章面向对象的软件设计A的一个属性记录了B对象;A要经常使用B对象B对象被创建时,A要传递初始化数据给B对象(3)低耦合(4)高内聚(5)控制者模式:要求把协调处理系统消息的职责分配给不同的控制类(6)多态:当某一个职责在不同的派生类中表现为不同的行为时,我们就可以使用多态模式,即利用一个同名的多态方法把该职责分配给不同的派生类,让他们履行不同的行为第6章面向对象的软件设计(7)纯虚构模式:有时我们可以虚构一个人造类,把一组高度内聚的职责分配给它,该人造类只是虚构出来的,不代表现实世界中的任何实体,这就是纯虚构模式。(8)中介者模式:把一些职责分配给一个虚构的中介类,让该中介类来协调多个类的协作关系(9)不要和陌生人说话:这个模式要求一个类尽量只和它的直接对象交互,避免和间接对象进行交互,这样,它就可以和最少的类产生耦合,使整个系统的耦合度保持最低。第6章面向对象的软件设计6.4面向对象软件实现面向对象实现阶段的主要任务:选择合适的面向对象的编程语言与开发环境;基于选定的语言和开发环境编码实现详细设计中所得到的对象、算法、公式和规则等;将编写好的各个类代码模块根据类的相互关系集成;对软件进行测试和调试,完成各个部分和整个系统。第6章面向对象的软件设计6.4.1程序设计语言1.面向对象语言的技术特点(1)支持类与对象概念的机制(2)实现整体/部分结构的机制(3)实现一般/特殊结构的机制(4)对于实现属性和服务的机制(5)类型检查(6)类库第6章面向对象的软件设计(7)效率(8)持久保存对象(9)参数化类(10)开发环境2.面向对象语言的选择(1)可复用性(2)类库和开发环境(3)其他因素第6章面向对象的软件设计6.4.2程序设计风格1.提高可重用性(1)提高方法的内聚(2)减小方法的规模(3)保持方法的一致性(4)把策略与实现分开(5)全面覆盖(6)尽量不使用全局信息(7)利用继承机制第6章面向对象的软件设计2.提高可扩充性(1)封装实现策略(2)不要用一个方法遍历多条关联链(3)避免使用多分支语句(4)精心确定公有方法3.提高健壮性(1)预防用户的操作错误(2)检查参数的合法性(3)不要预先确定限制条件(4)先测试后优化第6章面向对象的软件设计6.4.3面向对象软件测试1.面向对象的单元测试(1)类层测试(2)对象集群层测试2.面向对象的集成测试(1)基于线程的测试(2)基于使用的测试3.面向对象软件的高级测试第6章面向对象的软件设计4.面向对象软件测试用例(1)基于故障的测试用例设计是通过对面向对象分析与设计模型的分析,找出可能存在的故障,以此假设故障来设计测试用例,并通过这些测试用例确定这些可能的故障是否存在。基于故障的测试用例不能发现有错误的功能描述,或者子系统间交互引起的问题。(2)基于用例的测试用例设计关注用户“做什么”而不是软件“做什么”。通过测试用例获得用户必须完成的任务,并以此为依据设计所涉及的各个类的测试用例。第6章面向对象的软件设计设计面向对象软件测试用例的步骤是:(1)先选定检测的类(2)确定测试覆盖标准(3)利用类图确定待测试类的所有关联(4)根据程序中的对象设计测试用例,确认使用什么输入激发类的状态、使用类的服务和期望产生什么行为等。第6章面向对象的软件设计5.基于场景的测试设计基于场景的测试关注用户“做什么”而不是软件“做什么”。它意味着捕获用户必须完成的任务(通过使用实例),然后应用它们或它们的变体作为测试。第6章面向对象的软件设计6.测试表层结构和深层结构表层结构指面向对象程序外部可观察的结构,即对终端用户立即可见的结构。不是处理函数,而是很多面向对象系统的用户可能被给定一些以某种方式操纵的对象。深层结构指面向对象程序内部的技术细节,即通过检查设计和代码而理解的结构。深层结构测试被设计用以测试作为面向对象系统的子系统和对象设计的一部分而建立的依赖、行为和通信机制。分析和设计模型被用作深层结构测试的基础。