1.67k likes | 1.89k Views
第七讲 面向对象设计. 面向对象设计的准则 启发规则 软件重用 系统分解 设计问题域子系统. 设计人机交互子系统 设计任务管理子系统 设计数据管理子系统 设计类中的服务 设计关联 设计优化. 1 、面向对象设计的含义. 分析 是提取和整理用户需求,并建立问题域精确模型的过程。 设计 是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。 从面向对象分析到面向对象设计 (OOD) ,是一个逐渐扩充模型的过程。 面向对象设计 ( Object-Oriented Design , OOD )就是运用面向对象方法进行系统设计。.
E N D
第七讲 面向对象设计 • 面向对象设计的准则 • 启发规则 • 软件重用 • 系统分解 • 设计问题域子系统 • 设计人机交互子系统 • 设计任务管理子系统 • 设计数据管理子系统 • 设计类中的服务 • 设计关联 • 设计优化
1、面向对象设计的含义 • 分析是提取和整理用户需求,并建立问题域精确模型的过程。 • 设计是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。 • 从面向对象分析到面向对象设计(OOD),是一个逐渐扩充模型的过程。 • 面向对象设计(Object-Oriented Design,OOD)就是运用面向对象方法进行系统设计。
分析与设计的关联 人机交互部分 数据口部分 增补其它四个部分,成为完整的OOD模型。 任务管理部分 • 1、从OOA到OOD不是转换;是调整和增补 将OOA模型搬到OOD; 进行必要的调整, 作为OOD模型的问题域部分; OOA 模型 构件部署 问题域 部分
分析与设计的关联 • 2、采用一致的概念和表示法 • ——不存在分析与设计之间的鸿沟
分析与设计的关联 • 3、有不同的侧重点和不同的策略 • OOA主要针对问题域,识别有关的对象以及它们之间的关系,产生一个映射问题域,满足用户需求,独立于实现的OOA模型。 • OOD主要解决与实现有关的问题,基于OOA模型,针对具体的软、硬件条件(如机器、网络、OS、GUI、DBMS、编程语言等)产生一个可实现的OOD模型。
分析与设计的关联 • 4、OOA与OOD可适合不同的生命周期模型 • ——瀑布模型、螺旋模型、增量模型、喷泉模型 演化 分析 (OOA) 集成 设计 (OOD) 测试 喷泉模型 瀑布模型 编程 (OOP) 编程 (OOP) 设计 (OOD) 测试 分析 (OOA) 维护
面向对象设计的主要工作包括: • — 确定需要的类; • — 给每个类提供一组完整的操作; • — 明确地使用继承来表现共同点。 • 概括地说,面向对象设计就是“根据需求决定所需的类、类的操作,以及类之间关联的过程”。
OOD模型和过程 从一个侧面观察 OOD模型包括几个主要部分 ——一个核心部分加几个外围部分 • OOD模型——从两个侧面来描述 从另一侧面观察 OOD模型每个部分 如何用OO概念表达 ——采用OOA的概念及模型组织方式 在辅助模型中要增加分别用于描述构件模型和部署模型的构件图和部署图
2 软件设计原则 • 1.模块化 • 支持系统分解成模块的设计原则:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。 • 2.抽象 • 面向对象方法不仅支持过程抽象,而且支持数据抽象。 • 3.信息隐藏 • 在面向对象方法中,信息隐藏通过对象的封装性来实现。 • 4.低耦合 • 对象是最基本的模块,耦合主要指不同对象之间相互关联的紧密程度。低耦合是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其他部分的影响降到最低程度。 • 5.高内聚 • 操作内聚、类内聚、一般-具体内聚。
面向对象设计原则 • 最基本的设计原则有5条,分别是:单一职责原则、开放封闭原则、依赖倒置原则、接口隔离原则和Liskov替换原则。 • 单一职责原则 • 对于单一职责原则,其核心思想为:一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
开放封闭原则 • 对于开放封闭原则,它是面向对象所有原则的核心,软件设计说到底追求的目标就是封装变化、降低耦合,而开放封闭原则就是这一目标的最直接体现。开放封闭原则,其核心思想是:软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。
依赖倒置原则 • 对于依赖倒置原则,其核心思想是:依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。 • 依赖一定会存在于类与类、模块与模块之间。当两个模块之间存在紧密的耦合关系时,最好的方法就是分离接口和实现:在依赖之间定义一个抽象的接口使得高层模块调用接口,而底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标。
接口隔离原则 • 对于接口隔离原则,其核心思想是:使用多个小的专门的接口,而不要使用一个大的总接口 • 具体而言,接口隔离原则体现在:接口应该是内聚的,应该避免“胖”接口。一个类对另外一个类的依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染 • 分离的手段主要有以下两种:1、委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,但是会增加系统的开销。2、多重继承分离,通过接口多继承来实现客户的需求,这种方式是较好的。
Liskov替换原则 • Liskov替换原则,核心思想是:子类必须能够替换其基类。在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类可以替换基类,但是基类不一定能替换子类。 • Liskov替换原则,实现的方法是面向接口编程:将公共部分抽象为基类接口或抽象类,通过Extract Abstract Class,在子类中通过覆写父类的方法实现新的方式支持同样的职责。
3“软件重用”主要内容 • 概述 • 类构件 • 软件重用的效益
3.1软件重用概述 • 重用也叫再用或复用,是指同一事物不作修改或稍加改动就多次重复使用。 • 软件重用可分为以下3个层次: • 知识重用(例如,软件工程知识的重用)。 • 方法和标准的重用(例如,面向对象方法或国家制定的软件开发规范的重用)。 • 软件成分的重用。 • 前两个重用层次属于知识工程研究的范畴,本节仅讨论软件成分重用问题。
软件成分的重用级别 • 软件成分的重用可以进一步划分成以下3个级别: • 代码重用。谈论最多,通常理解为调用库中的模块。 • 设计结果重用。重用某个软件系统的设计模型(即求解域模型)。这个级别的重用有助于把一个应用系统移植到完全不同的软硬件平台上。 • 分析结果重用。这是更高级别的重用,即重用某个系统的分析模型。它特别适用于用户需求未改变,但系统体系结构发生了根本变化的场合。
典型的可重用软件成分 • 项目计划。 • 成本估计。 • 体系结构。 • 需求模型和规格说明。 • 设计。 • 源代码。 • 用户文档和技术文档。 • 用户界面。 • 数据。 • 测试用例。
3.2类构件 • 利用面向对象技术,可以更方便更有效地实现软件重用。 • 面向对象技术中的“类”,是比较理想的可重用软构件,不妨称之为类构件。 • 可重用软构件应具备的特点: • 模块独立性强。 • 具有高度可塑性。 • 接口清晰、简明、可靠。 • 类构件的重用方式:实例重用/继承重用/多态重用
a实例重用的形式 • 最基本的重用方式: • 由于类的封装性,使用者无须了解实现细节就可以使用适当的构造函数,按照需要创建类的实例。 • 然后向所创建的实例发送适当的消息,启动相应的服务,完成需要完成的工作。 • 如:一个类名是Person,Person p=new Person() • 另一种形式:用几个简单的对象作为类的成员创建出一个更复杂的类。 • 如:类User中的属性有 • Person p=null;
b继承重用 • 面向对象方法特有的继承性提供了一种对已有的类构件进行裁剪的机制。 • 当已有的类构件不能通过实例重用完全满足当前系统需求时,继承重用提供了一种安全地修改已有类构件,以便在当前系统中重用的手段。
已有类 • 如:问题域类
c多态重用 • 利用多态性不仅可以使对象的对外接口更加一般化(基类与派生类的许多对外接口是相同的),从而降低了消息连接的复杂程度,而且还提供了一种简便可靠的软构件组合机制。 • 系统运行时,根据接收消息的对象类型,由多态性机制启动正确的方法,去响应一个一般化的消息,从而简化了消息界面和软构件连接过程。
3.3软件重用的效益 • 近来,软件产业界的实例研究表明,通过积极的软件重用能够获得可观的商业效益,产品质量、开发生产率和整体成本都得到改善。 • 软件重用的效益可表现在以下几个方面: • 质量: • 生产率 • 成本
软件重用的效益-1质量 • 理想状态下,为了重用而开发的软构件已被证明是正确的,且没有缺陷。 • 事实上,由于不能定期进行形式化验证,错误可能而且也确实存在 • 但是,随着每一次重用,都会有一些错误被发现并被清除,构件的质量也会随之改善。随着时间的推移,构件将变成实质上无错误的 • HP公司经研究发现,被重用的代码的错误率是每千行代码中有0.9个错误,而新开发的软件的错误率是每千行代码中有4.1个错误。对于一个包含68%重用代码的应用系统,错误率大约是每千行2.0个错误,与不使用重用的开发相比错误率降低了51% • 公正地说,重用确实能给软件产品的质量和可靠性带来实质性的提高。
软件重用的效益-2生产率 • 当把可重用的软件成分应用于软件开发的全过程时,创建计划、模型、文档、代码和数据所需花费的时间将减少,从而将用较少的投入给客户提供相同级别的产品,因此,生产率得到了提高。 • 由于应用领域、问题复杂程度、项目组的结构和大小、项目期限、可应用的技术等许多因素都对项目组的生产率有影响,因此,不同开发组织对软件重用带来生产率提高的数字的报告并不相同,但基本上30%~50%的重用大约可以导致生产率提高25%~40%。
软件重用的效益-3成本 • 软件重用能节省的净成本节省可估算为:C=Cs-Cr-Cd • Cs是项目从头开发(没有重用)时所需要的成本; • Cr是与重用相关联的成本; • Cd是交付给客户的软件的实际成本。 • 可使用一定的技术来估算Cs,而与重用相关联的成本Cr主要包括: • 领域分析与建模的成本; • 设计领域体系结构的成本; • 为便于重用而增加的文档的成本; • 维护和完善可重用的软件成分的成本; • 为从外部获取构件所付出的版税和许可证费; • 创建(或购买)及运行重用库的费用; • 对设计和实现可重用构件的人员的培训费用。
4 系统分解与子系统 • 在设计比较复杂的应用系统时普遍采用的策略,是首先把系统分解成若干个比较小的部分,然后再分别设计每个部分。 • 系统的主要组成部分称为子系统: • 通常根据所提供的功能来划分子系统。 • 一般说来,子系统的数目应该与系统规模基本匹配。 • 各个子系统之间应该具有尽可能简单、明确的接口。 • 接口确定交互形式和通过子系统边界的信息流,无须规定子系统内部的算法。可以独立地设计各子系统 • 在划分和设计子系统时,应该尽量减少子系统彼此间的依赖性。
面向对象设计模型 • 大多数系统的面向对象设计模型: • 在逻辑上由4部分组成:人机交互部分、问题域部分、任务管理部分、数据管理部分 • 这4部分对应于组成目标系统的4个子系统:问题域子系统、人机交互子系统、任务管理子系统、数据管理子系统 • 不同的软件系统中,这4个子系统的重要程度和规模可能相差很大: • 规模过大的在设计过程中应该进一步划分成更小的子系统。 • 规模过小的可合并在其他子系统中,某些领域的应用系统在逻辑上可能仅由3个(甚至少于3个)子系统组成
5个层次与4大组成部分的关系 • 可以把面向对象设计模型的4大组成部分想象成整个模型的4个垂直切片。 • 典型的面向对象设计模型可以用下图表示:
子系统之间的交互方式 • 软件系统中,子系统之间的交互有两种可能方式: • 客户-供应商(Client-supplier)关系。 • 平等伙伴(peer-to-peer)关系。 • 总的说来,单向交互比双向交互更容易理解,也更容易设计和修改,因此应该尽量使用客户-供应商关系。
组织系统的方案 • 把子系统组织成完整的系统,有两种方案: • 水平层次组织 • 垂直块状组织
组织系统的方案-1水平层次组织 • 把软件系统组织成一个层次系统,每层是一个子系统。 • 上层在下层的基础上建立,下层为实现上层功能而提供必要的服务。 • 每一层内所包含的对象,彼此间相互独立,而处于不同层次上的对象,彼此间往往有关联。 • 实际上,在上、下层之间存在客户-供应商关系。
层次结构可划分为封闭式和开放式 • 层次结构又可进一步划分成两种模式: • 封闭式: • 每层子系统仅仅使用其直接下层提供的服务。 • 降低了各层次之间的相互依赖性,更容易理解和修改。 • 开放模式: • 某层子系统可以使用处于其下面的任何一层子系统所提供的服务。 • 优点,是减少了需要在每层重新定义的服务数目。 • 开放模式的系统不适合信息隐藏原则。 • 设计软件系统时到底采用哪种结构模式,需要权衡效率和模块独立性等多种因素,通盘考虑后再做决定。
系统顶层和底层的关系 • 通常,在需求陈述中只描述了对系统顶层和底层的需求: • 顶层就是用户看到的目标系统; • 底层则是可以使用的资源。 • 顶层和底层往往差异很大,设计者必须设计一些中间层次,以减少不同层次之间的概念差异。
组织系统的方案-2块状组织 • 这种组织方案把软件系统垂直地分解成若干个相对独立的、弱耦合的子系统,一个子系统相当于一块,每块提供一种类型的服务。
层次和块的混合结构 • 利用层次和块的各种可能的组合,可以成功地由多个子系统组成一个完整的软件系统。 • 当混合使用层次结构和块状结构时,同一层次可以由若干块组成,而同一块也可以分为若干层。 • 如图表示一个典型的应用系统的组织结构,这个应用系统采用了层次与块状的混合结构。
设计系统的拓扑结构 • 由子系统组成完整的系统时,典型的拓扑结构有: • 管道形 • 树形 • 星形 • 设计者应该采用与问题结构相适应的、尽可能简单的拓扑结构,以减少子系统之间的交互数量。
5 设计问题域子系统 按实现条件(编程语言,网络与操作系统,复用支持等)进行必要的调整。 OOA 模型 人机交互部分 数据管理部分 问题域 部分 将OOA模型搬到OOD 作为OOD的基础 任务管理部分 • 问题域是该系统处理的业务范围 • 问题域部分的设计要对OOA结果按实现条件进行补充与调整。即要继续运用OOA的方法,包括概念、表示法及一部分策略。
问题域模型在OO设计中的作用 • 通过面向对象分析所得出的问题域精确模型,为设计问题域子系统奠定了良好的基础,建立了完整的框架。 • 只要可能,就应该保持面向对象分析所建立的问题域结构。 • 通常,面向对象设计仅需从实现角度对问题域模型做一些补充或修改,主要是增添、合并或分解类与对象、属性及服务,调整继承关系等等。 • 当问题域子系统过分复杂庞大时,应该把它进一步分解成若干个更小的子系统。
OO可以保持问题域组织框架的稳定性 • 使用面向对象方法学开发软件,能够保持问题域组织框架的稳定性,从而便于追踪分析、设计和编程的结果。 • 在设计与实现过程中所做的细节修改(例如,增加具体类,增加属性或服务),并不影响开发结果的稳定性,因为系统的总体框架是基于问题域的。 • 对于需求可能随时间变化的系统来说,稳定性是至关重要的。 • 稳定性能够在类似系统中重用分析、设计和编程结果的关键因素。 • 为更好地支持系统在其生命周期中的扩充,也需要稳定性。
对问题域模型需要做的补充或修改 • (1)为复用设计与编程的类而增加结构 • (2)增加一般类以建立共同协议 • (3)按编程语言调整继承 • (4)提高性能 • (5)为数据存储管理增补属性与服务 • (6)为编程方便增加底层成分 • (7) 决定关系的实现方式 • (8)对例外的处理 • (9)编程语言限制了可用的属性类型 • (10)构造或优化算法 • (11)调整服务 • (12)决定对象间的可访问性 • (13) 考虑采用设计模式 • (14)其它
1、为复用设计与编程的类而增加结构 如果OOA识别和定义的类是本次开发中新定义的,需要进行编程。 如果已存在一些可复用的类,而且这些类既有分析、设计时的定义,又有源程序,那么,复用这些类即可提高开发效率与质量。 可复用的类可能只是与OOA模型中的类相似,而不是完全相同,因此需对其进行修改。 目标:尽可能使复用成分增多,新开发的成分减少
不同程度的复用 当前所需的类的信息 比 可复用类定义的信息 • = 直接复用 • < 通过继承复用 • > 删除可复用类的多余信息 • ≈ 删除多余信息,通过继承而复用
第四种情况的做法: (1)把要复用的类加到问题域,标以 “复用” (2)划掉(或标出)不用的属性与服务 (3)建立从复用类到问题域原有的类之间的泛化关系 (4)由于问题域的类继承了“复用”类的特征,所以有些属性和服务不需要了——划掉。
(复用) 车辆 车辆 序号 厂商 式样 序号认证 序号 厂商 式样 序号认证 可复用的类 可复用的类 问题域中的类 车辆 序号 颜色 式样 出厂年月 序号认证 例:
2、增加一般类以建立共同协议 增加根类:将所有的具有相似协议的类组织在一起 提供通用的协议 例:提供创建、删除、复制等服务 增加其他一般类:提供局部通用的协议 例:提供永久存储及恢复功能
3、按编程语言调整继承 起因:OOA强调如实地反映问题域,OOD考虑实现问题, 所用语言不支持多继承,甚至不支持继承 多继承模式 狭义菱形 广义菱形
B A C B A C (1)把多继承调整为单继承 方法1:采用聚合,将多继承转换为单继承 因为聚合和泛化是不同的概念,这种方法并不是通用的(按定义)。 在大多数情况下,需要考虑形成多继承的原因,将本来在特殊类中显式定义的信息分离出来,作为部分对象,以原来的一般类作为整体对象。