160
第第第 第第第第第第 第第第第第第第第第 第第第第第第第第第 第第第第 第第第第 第第第第 第第第第 第第 第第 第第第第第第第第第第第第第第 设设设设设设设设设设设设设设设设 设设设设设设设设设设设设设设设设 设设设设设设设设设设设设设设设设 设设设设设设设 设设设设设设设 设设设设 设设设设 设设设设 设设设设

第七讲 面向对象设计

Embed Size (px)

DESCRIPTION

第七讲 面向对象设计. 面向对象设计的准则 启发规则 软件重用 系统分解 设计问题域子系统. 设计人机交互子系统 设计任务管理子系统 设计数据管理子系统 设计类中的服务 设计关联 设计优化. 1 、面向对象设计的含义. 分析 是提取和整理用户需求,并建立问题域精确模型的过程。 设计 是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。 从面向对象分析到面向对象设计 (OOD) ,是一个逐渐扩充模型的过程。 面向对象设计 ( Object-Oriented Design , OOD )就是运用面向对象方法进行系统设计。. - PowerPoint PPT Presentation

Citation preview

Page 1: 第七讲  面向对象设计

第七讲 面向对象设计

面向对象设计的准则面向对象设计的准则启发规则启发规则软件重用软件重用系统分解系统分解设计问题域子系统设计问题域子系统

设计人机交互子系统设计人机交互子系统设计任务管理子系统设计任务管理子系统设计数据管理子系统设计数据管理子系统设计类中的服务设计类中的服务设计关联设计关联设计优化设计优化

Page 2: 第七讲  面向对象设计

1 、面向对象设计的含义

分析是提取和整理用户需求,并建立问题域精确模型的过程。

设计是把分析阶段得到的需求转变成符合成本和质量要求的、抽象的系统实现方案的过程。

从面向对象分析到面向对象设计 (OOD) ,是一个逐渐扩充模型的过程。

面向对象设计( Object-Oriented Design, OOD )就是运用面向对象方法进行系统设计。

Page 3: 第七讲  面向对象设计

分析与设计的关联 1 、从 OOA到 OOD 不是转换;是调整和增补

问题域部分

OOA模型

将 OOA 模型搬到 OOD ;进行必要的调整,作为 OOD 模型的问题域部分;

人机交互部分

数据口部分

任务管理部分

增补其它四个部分,成为完整的 OOD 模型。

构件部署

Page 4: 第七讲  面向对象设计

分析与设计的关联

2 、采用一致的概念和表示法 —— 不存在分析与设计之间的鸿沟

Page 5: 第七讲  面向对象设计

分析与设计的关联

3 、有不同的侧重点和不同的策略 OOA 主要针对问题域,识别有关的对象以

及它们之间的关系,产生一个映射问题域,满足用户需求,独立于实现的 OOA 模型。

OOD 主要解决与实现有关的问题,基于OOA 模型,针对具体的软、硬件条件(如机器、网络、 OS、 GUI、 DBMS 、编程语言等)产生一个可实现的 OOD 模型。

Page 6: 第七讲  面向对象设计

分析与设计的关联 4 、OOA与OOD 可适合不同的生命周期模型

—— 瀑布模型、螺旋模型、增量模型、喷泉模型分析

(OOA)

设计(OOD)

编程(OOP)

演化

集成

测试

编程(OOP)

设计(OOD)

分析(OOA)

测试

维护

瀑布模型喷泉模型

Page 7: 第七讲  面向对象设计

面向对象设计的主要工作包括:— 确定需要的类;— 给每个类提供一组完整的操作;— 明确地使用继承来表现共同点。概括地说,面向对象设计就是“根据需求决定

所需的类、类的操作,以及类之间关联的过程”。

Page 8: 第七讲  面向对象设计

OOD 模型和过程

OOD 模型——从两个侧面来描述

从另一侧面观察OOD 模型每个部分

如何用 OO 概念表达—— 采用 OOA 的概念及模型组织方式

从一个侧面观察OOD 模型包括几个主要部分—— 一个核心部分

加几个外围部分

在辅助模型中要增加分别用于描述构件模型和部署模型的构件图和部署图

Page 9: 第七讲  面向对象设计

2 软件设计原则 1 .模块化

支持系统分解成模块的设计原则:对象就是模块。它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。

2 .抽象 面向对象方法不仅支持过程抽象,而且支持数据抽象。

3 .信息隐藏 在面向对象方法中,信息隐藏通过对象的封装性来实现。

4 .低耦合 对象是最基本的模块,耦合主要指不同对象之间相互关联的紧密

程度。低耦合是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其他部分的影响降到最低程度。

5 .高内聚 操作内聚、类内聚、一般-具体内聚。

Page 10: 第七讲  面向对象设计

面向对象设计原则

最基本的设计原则有 5 条,分别是:单一职责原则、开放封闭原则、依赖倒置原则、接口隔离原则和 Liskov替换原则。

单一职责原则对于单一职责原则,其核心思想为:一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。

Page 11: 第七讲  面向对象设计

开放封闭原则对于开放封闭原则,它是面向对象所有原则的核心

,软件设计说到底追求的目标就是封装变化、降低耦合,而开放封闭原则就是这一目标的最直接体现。开放封闭原则,其核心思想是:软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。

Page 12: 第七讲  面向对象设计

依赖倒置原则对于依赖倒置原则,其核心思想是:依赖于抽象。

具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。

依赖一定会存在于类与类、模块与模块之间。当两个模块之间存在紧密的耦合关系时,最好的方法就是分离接口和实现:在 依赖之间定义一个抽象的接口使得高 层模块调用接口,而 底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标。

Page 13: 第七讲  面向对象设计

接口隔离原则 对于接口隔离原则,其核心思想是:使用多个小的专门的接口,而不要使用一个 大的总接口

具体而言,接口隔离原则体现在:接口应该是内聚的,应该避免“胖”接口。一个类对另外一个类的 依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染

分离的手段主要有以下两种: 1 、委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,但是会增加系统的开销。 2 、多重继承分离,通过接口多继承来实现客户的需求,这种方式是较好的。

Page 14: 第七讲  面向对象设计

Liskov替换原则Liskov替换原则,核心思想是:子类必须能够替

换其基类。在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类可以替换基类,但是基类不一定能替换子类。

Liskov替换原则,实现的方法是面向接口编程:将公共部分抽象为基类接口或抽象类,通过Extract Abstract Class ,在子类中通过覆写父类的方法实现新的方式支持同样的职责。

Page 15: 第七讲  面向对象设计

3“ 软件重用”主要内容

概述类构件软件重用的效益

Page 16: 第七讲  面向对象设计

3.1 软件重用概述 重用也叫再用或复用,是指同一事物不作修改或稍加改动就多次重复使用。

软件重用可分为以下 3 个层次:1. 知识重用 ( 例如,软件工程知识的重用 ) 。2. 方法和标准的重用 ( 例如,面向对象方法或国家制

定的软件开发规范的重用 ) 。3. 软件成分的重用。

前两个重用层次属于知识工程研究的范畴,本节仅讨论软件成分重用问题。

Page 17: 第七讲  面向对象设计

软件成分的重用级别

软件成分的重用可以进一步划分成以下 3 个级别:1. 代码重用。谈论最多 ,通常理解为调用库中的模块。2. 设计结果重用。重用某个软件系统的设计模型 ( 即求解

域模型 ) 。这个级别的重用有助于把一个应用系统移植到完全不同的软硬件平台上。

3. 分析结果重用。这是更高级别的重用,即重用某个系统的分析模型。它特别适用于用户需求未改变,但系统体系结构发生了根本变化的场合。

Page 18: 第七讲  面向对象设计

典型的可重用软件成分1. 项目计划。2. 成本估计。3. 体系结构。4. 需求模型和规格说明。5. 设计。6. 源代码。7. 用户文档和技术文档。8. 用户界面。9. 数据。10.测试用例。

Page 19: 第七讲  面向对象设计

3.2 类构件

利用面向对象技术,可以更方便更有效地实现软件重用。

面向对象技术中的“类”,是比较理想的可重用软构件,不妨称之为类构件。

可重用软构件应具备的特点:1. 模块独立性强。2. 具有高度可塑性。3. 接口清晰、简明、可靠。

类构件的重用方式 : 实例重用 /继承重用 / 多态重用

Page 20: 第七讲  面向对象设计

a 实例重用的形式

最基本的重用方式:由于类的封装性,使用者无须了解实现细节就可以使

用适当的构造函数, 按照需要创建类的实例。然后向所创建的实例发送适当的消息,启动相应的服

务,完成需要完成的工作。如:一个类名是 Person, Person p=new

Person ()另一种形式:用几个简单的对象作为类的成员创

建出一个更复杂的类。如:类 User 中的属性有Person p=null ;

Page 21: 第七讲  面向对象设计

b 继承重用

面向对象方法特有的继承性提供了一种对已有的类构件进行裁剪的机制。

当已有的类构件不能通过实例重用完全满足当前系统需求时,继承重用提供了一种安全地修改已有类构件,以便在当前系统中重用的手段。

Page 22: 第七讲  面向对象设计

已有类

Person

用户名性别工作单位电话

如:问题域类User

用户名密码性别工作单位电话

Person

用户名性别工作单位电话

User

密码

Page 23: 第七讲  面向对象设计

c 多态重用

利用多态性不仅可以使对象的对外接口更加一般化 ( 基类与派生类的许多对外接口是相同的 ) ,从而降低了消息连接的复杂程度,而且还提供了一种简便可靠的软构件组合机制。

系统运行时,根据接收消息的对象类型,由多态性机制启动正确的方法,去响应一个一般化的消息,从而简化了消息界面和软构件连接过程。

Page 24: 第七讲  面向对象设计

User

login ()

Student

login ()

Administrator

login ()

Page 25: 第七讲  面向对象设计

3.3 软件重用的效益 近来,软件产业界的实例研究表明,通过积极的软件

重用能够获得可观的商业效益,产品质量、开发生产率和整体成本都得到改善。

软件重用的效益可表现在以下几个方面:1. 质量:2. 生产率3. 成本

Page 26: 第七讲  面向对象设计

软件重用的效益 -1 质量 理想状态下,为了重用而开发的软构件已被证明是正确的

,且没有缺陷。 事实上,由于不能定期进行形式化验证,错误可能而且也确实存在 但是,随着每一次重用,都会有一些错误被发现并被清除,构件的

质量也会随之改善。随着时间的推移,构件将变成实质上无错误的 HP公司经研究发现,被重用的代码的错误率是每千行代码

中有 0.9 个错误,而新开发的软件的错误率是每千行代码中有 4.1 个错误。对于一个包含 68% 重用代码的应用系统,错误率大约是每千行 2.0 个错误,与不使用重用的开发相比错误率降低了 51%

公正地说,重用确实能给软件产品的质量和可靠性带来实质性的提高。

Page 27: 第七讲  面向对象设计

软件重用的效益 -2 生产率当把可重用的软件成分应用于软件开发的全过程时,创

建计划、模型、文档、代码和数据所需 花费的时间将减少,从而将用较少的投入给客户提供相同级别的产品,因此,生产率得到了提高。

由于应用领域、问题复杂程度、项目组的结构和大小、项目期限、可应用的技术等许多因素都对项目组的生产率有影响,因此,不同开发组织对软件重用带来生产率提高的数字的报告并不相同,但基本上 30%~50% 的重用大约可以导致生产率提高 25%~40% 。

Page 28: 第七讲  面向对象设计

软件重用的效益 -3 成本 软件重用能节省的净成本节省可估算为: C=Cs-Cr-Cd

Cs 是项目从头开发(没有重用)时所需要的成本; Cr 是与重用相关联的成本; Cd 是交付给客户的软件的实际成本。

可使用一定的技术来估算 Cs ,而与重用相关联的成本 Cr 主要包括: 领域分析与建模的成本; 设计领域体系结构的成本; 为便于重用而增加的文档的成本; 维护和完善可重用的软件成分的成本; 为从外部获取构件所付出的版税和许可证费; 创建(或购买)及运行重用库的费用; 对设计和实现可重用构件的人员的培训费用。

Page 29: 第七讲  面向对象设计

4 系统分解与子系统 在设计比较复杂的应用系统时普遍采用的策略,是首先把

系统分解成若干个比较小的部分,然后再分别设计每个部分。

系统的主要组成部分称为子系统:通常根据所提供的 功能来划分子系统。一般说来,子系统的数目应该与系统规模基本匹配。各个子系统之间应该具有尽可能简单、明确的接口。接口确定交互 形式和通过子系统边界的信息流,无须规定子系统内部的算法。可以独立地设计各子系统

在划分和设计子系统时,应该尽量减少子系统彼此间的依赖性。

Page 30: 第七讲  面向对象设计

面向对象设计模型大多数系统的 面向对象设计模型:

在逻辑上由 4 部分组成:人机交互部分、问题域部分、任务管理部分、数据管理部分

这 4 部分对应于组成目标系统的 4 个子系统:问题域子系统、人机交互 子系统、任务管理子系统、数据管理 子系统

不同的软件系统中,这 4 个子系统的重要程度和规模可能相差很大:•规模过大的在设计过程中应该进一步划分成更小的子系

统。•规模过小的可合并在其他子系统中,某些领域的应用系

统在逻辑上可能仅由 3 个 ( 甚至少于 3 个 ) 子系统组成

Page 31: 第七讲  面向对象设计

5 个层次与 4 大组成部分的关系

可以把面向对象设计模型的 4 大组成部分想象成整个模型的 4 个垂直切片。

典型的面向对象设计模型可以用下图表示:

Page 32: 第七讲  面向对象设计

子系统之间的交互方式 软件系统中,子系统之间的交互有两 种可能方

式 : 客户 -供应商 (Client-supplier) 关系。 平等伙伴 (peer-to-peer) 关系。

总的说来,单向交互 比双向交互 更容易理解,也更容易设计和修改,因此应该尽量使用客户 -供应商关系。

Page 33: 第七讲  面向对象设计

组织系统的方案

把子系统组织成完整的系统,有两种方案:水平层次组织垂直块状组织

Page 34: 第七讲  面向对象设计

组织系统的方案 -1 水平层次组织

把软件系统组织成一个层次系统,每层是一个子系统。上层在下层的基础上建立,下层为实现上层功能而提供

必要的服务。每一层内所包含的对象,彼此间相互独立,而 处于不同层次上的对象,彼此间往往有关联。

实际上,在上、下层之间存在客户 -供应商关系。

Page 35: 第七讲  面向对象设计

层次结构可划分为封闭式和开放式层次结构又可进一步划分成两种模式:

封闭式:• 每层子系统仅仅使用其直接下层提供的服务。• 降低了各层次之间的相互依赖性,更容易理解和修改。

开放模式:• 某层子系统可以使用处于其下面的任何一层子系统所提

供的服务。•优点,是减少了需要在每层重新定义的服务数目。•开放模式的系统不适合信息隐藏原则。

设计软件系统时到底采用哪种结构模式,需要权衡效率和模块独立性等多种因素,通盘考虑后再做决定。

Page 36: 第七讲  面向对象设计

系统顶层和底层的关系通常,在需求陈述中只描述了对系统顶层和底层的

需求:顶层就是用户看到的目标系统;底层则是可以使用的资源。

顶层和底层往往差异很大,设计者必须设计一些中间层次,以减少不同层次之间的概念差异。

Page 37: 第七讲  面向对象设计

组织系统的方案 -2 块状组织这种组织方案把软件系统垂直地分解成若干个相对

独立的、弱耦合的子系统,一个子系统相当于一块,每块提供一种类型的服务。

Page 38: 第七讲  面向对象设计

层次和块的混合结构利用层次和块的各种可能的组合,可以成功地由多个子系

统组成一个完整的软件系统。当混合使用层次结构和块状结构时,同一层次可以由若干

块组成,而同一块也可以分为若干层。 如图表示一个典型的应用系统的组织结构,这个应用系统

采用了层次与块状的混合结构。

Page 39: 第七讲  面向对象设计

设计系统的拓扑结构

由子系统组成完整的系统时,典型的拓扑结构有:管道形树形星形

设计者应该采用与问题结构相适应的、尽可能简单的拓扑结构,以减少子系统之间的交互数量。

Page 40: 第七讲  面向对象设计

问题域是该系统处理的业务范围 问题域部分的设计要对 OOA 结果按实现条件进行补充与

调整。即要继续运用 OOA 的方法,包括概念、表示法及一部分策略。

5 设计问题域子系统

将 OOA 模型搬到 OOD作为 OOD 的基础

人机交互部分

数据管理部分

任务管理部分

问题域部分

OOA模型

按实现条件(编程语言,网络与操作系统,复用支持等)进行必要的调整。

Page 41: 第七讲  面向对象设计

问题域模型在 OO 设计中的作用 通过面向对象分析所得出的问题域精确模型,为设计问

题域子系统奠定了良好的基础,建立了完整的框架。 只要可能,就应该保持面向对象分析所建立的问题域结

构。 通常,面向对象设计仅需从实现角度对问题域模型做一

些补充或修改,主要是增添、合并或分解类与对象、属性及服务,调整继承关系等等。

当问题域子系统过分复杂庞大时,应该把它进一步分解成若干个更小的子系统。

Page 42: 第七讲  面向对象设计

OO 可以保持问题域组织框架的稳定性

使用面向对象方法学开发软件,能够保持问题域组织框架的稳定性,从而便于追踪分析、设计和编程的结果。

在设计与实现过程中所做的细节修改 ( 例如,增加具体类,增加属性或服务 ) ,并不影响开发结果的稳定性,因为系统的总体框架是基于问题域的。

对于需求可能随时间变化的系统来说,稳定性是至关重要的。 稳定性能够在类似系统中重用分析、设计和编程结果的关键因素

。 为更好地支持系统在其生命周期中的扩充,也需要稳定性。

Page 43: 第七讲  面向对象设计

对问题域模型需要做的补充或修改

( 1 )为复用设计与编程的类而增加结构 ( 2 )增加一般类以建立共同协议 ( 3 )按编程语言调整继承 ( 4 )提高性能 ( 5 )为数据存 储管理增补属性与服务 ( 6 )为编程方便增加底层成分

( 7 ) 决定关系的实现方式 ( 8 )对例外的处理 ( 9 )编程语言限制了可用的属性类型 ( 10 )构造或优化算法

( 11 )调整服务 ( 12 )决定对象间的可访问性 ( 13) 考虑采用设计模式 ( 14 )其它

Page 44: 第七讲  面向对象设计

1 、为复用设计与编程的类而增加结构

如果 OOA 识别和定义的类是本次开发中新定义的,需要进行编程。

如果已存在一些可复用的类,而且这些类既有分析、设计时的定义,又有源程序,那么,复用这些类即可提高开发效率与质量。

可复用的类可能只是与 OOA 模型中的类相似,而不是完全相同,因此需对其进行修改。

目标:尽可能使复用成分增多,新开发的成分减少

Page 45: 第七讲  面向对象设计

不同程度的复用

当前所需的类的信息

可复用类定义的信息

= 直接复用

< 通过继承复用

> 删除可复用类的多余信息

≈ 删除多余信息,通过继承而复用

Page 46: 第七讲  面向对象设计

第四种情况的做法:

( 1 )把要复用的类加到问题域,标以 “复用”( 2 )划掉(或标出)不用的属性与服务( 3 )建立从复用类到问题域原有的类之间的泛化关系( 4 )由于问题域的类继承了“复用”类的特征,所以有些属性和服务不需要了——划掉。

Page 47: 第七讲  面向对象设计

例:

序号颜色式样出厂年月序号认证

车辆序号厂商式样序号认证

可复用的类车辆

问题域中的类

(复用)车辆序号厂商式样序号认证

可复用的类

Page 48: 第七讲  面向对象设计

2 、增加一般类以建立共同协议

增加根类:将所有的具有相似协议的类组织在一起 提供通用的协议

例:提供创建、删除、复制等服务

增加其他一般类:提供局部通用的协议例:提供永久存储及恢复功能

Page 49: 第七讲  面向对象设计

3 、按编程语言调整继承起因: OOA强调如实地反映问题域, OOD考虑实现问题,

所用语言不支持多继承,甚至不支持继承

多继承模式

狭义菱形 广义菱形

Page 50: 第七讲  面向对象设计

BA

C

BA

C

因为聚合和泛化是不同的概念,这种方法并不是通用的 ( 按定义 ) 。

在大多数情况下,需要考虑形成多继承的原因,将本来在特殊类中显式定义的信息分离出来,作为部分对象,以原来的一般类作为整体对象。

( 1 )把多继承调整为单继承 方法 1 :采用聚合,将多继承转换为单继承

Page 51: 第七讲  面向对象设计

案例:采用聚合,将多继承转换为单继承

公司人员

雇主 职员

雇主职员

公司人员

身份

雇主身份 职员身份

1..2

1

Page 52: 第七讲  面向对象设计

方法 2 :压平

公司人员

雇主 职员雇主职员

问题:有什么缺点?

Page 53: 第七讲  面向对象设计

公司人员

雇主 职员雇主职员

雇主信息 职员信息

如何解决?

Page 54: 第七讲  面向对象设计

( 2 )取消泛化

雇主 职员雇主职员

方法二:使用聚合代替继承

方法一:把继承的结构展平

Page 55: 第七讲  面向对象设计

( 3 )对多态性的调整

Page 56: 第七讲  面向对象设计

•把需要频繁交换信息的对象, 尽量地放在一台处理机上。 •增加属性或类,以保存中间结果•提高或降低系统的并发度,可能要人为地增加 或减少主动对象。•合并通讯频繁的类

流速调节器

指定流速……

流速调节… …

流速探测器

当前流速……

流速探测取当前流速… …

流速控制器

指定流速当前流速……

流速调节流速探测… …

合并前 合并后

4 、提高性能

Page 57: 第七讲  面向对象设计

•用聚合关系描述复杂类 帧

显示

背景 前景

* 1

1 1

显示显示

Page 58: 第七讲  面向对象设计

•为编程方便增加底层成分——细化对象的分类

例:将几何图形分成多边形、椭圆、扇形等特殊类

几何图形

多边形 扇形椭圆

Page 59: 第七讲  面向对象设计

59

学生 教师

1..* 1..*

教师 - 学生

教师编号学生编号…….

11

学生 教师

1..*1..*把多对多关联转化为一对多关联

5 、对复杂关联的转化并决定关联的实现方式

Page 60: 第七讲  面向对象设计

项目

人员

语言

语言项目

人员

任务项

项目名

人员

语言

……1 1..*

* 1

1 ..*

1..*

把多元关联转化为二元关联

Page 61: 第七讲  面向对象设计

6 、调整与完善属性 按照语法: [ 可见性 ] 属性名 [‘ :’类型 ][‘=’ 初始值 ] 对属性的定义进行完善。每一个属性或者包含单个值,或者包含作为一个整体的密切相关的一组值。

若要给出对属性的性质的约束,如“工龄 <60”或“ 0≤英语成绩≤ 100” 等,也要看语言是否对其直接支持,否则要在算法上考虑如何实现。

Page 62: 第七讲  面向对象设计

7 、构造和优化算法

对于需要设计的操作,要从如下几方面进行详细地定义: ( 1 ) 按照定义操作的格式: [ 可见性 ] 操作名 [‘(’参数列表‘ )’][‘:’返回类型 ] 完善操作的定义。 ( 2 )从问题域的角度,根据其 责任,考虑实现操作的算法,即对象是怎样提供操作的。 ( 3 )若操作有前后置条件或不变式,考虑编程语言是否予以支持。若不支持,在操作的方法中要予以实现。 ( 4 )建议进一步地分析特定类的对象相关的所有交互图, 找出其所有与之相关的消息。一个对象所要响应的每个消息都要由该对象的操作处理,其中的一个操作也可能要使用其他操作。 如果类拥有状态图,还可根据内部转换以及外部转换 上的动作,设计算法的详细逻辑。 可用自然语言或进行了一定结构化的自然语言描述算法,也可以使用程序框图或活动图描述算法。 ( 5 ) 在算法中还要考虑对例外和特殊情况的处理。如考虑对输入错误、来自中间件或其它软硬件的错误的消息以及其它例外情况的处理。 ( 6 ) 在系统较为复杂或需要处理大批量的数据的 情况下,若系统在性能上有要求,就要对系统的体系结构和算法进行优化。

Page 63: 第七讲  面向对象设计

8 、 其它

在 OOD 的问题域部分应该根据具体问题 考虑使用设计模式。

在 OOD 的问题域部分,根据情况,还有一些其它需要考虑的问题。例如,考虑加入进行输入数据 验证这样的类;考虑对来自中间件或其它软硬件的错误进行处理的类,以及对其它例外情况进行处理的类。

Page 64: 第七讲  面向对象设计

6 设计人机交互子系统

在OOA 过程中,已对用户界面需求做了初步分析。

在OOD 过程中,应该对系统的人机交互 子系统进行详细设计,以确定人机交互的 细节,其中包括指定窗口和 报表的形式、设计命令层等项内容。

利用 OOD 设计人机交互 子系统的步骤: 分类用户 描述用户 设计命令层次 设计人机交互类

控制接口部分

问题域部分

数据管理部分

人机交互部分

OSF/Motif

人机交互部分 X-Window

人机交互部分 MS-Windows

Page 65: 第七讲  面向对象设计

人机交互子系统 -1 分类用户 人机交互 界面是给用户用的,设计者应该认真研究这些用

户。 1 、分析与系统交互的人 ——人员参与者

人对 界面的需求,不仅在于人机交互的内 容,而且在于他们对界面表现形式、风格等方面的爱好。

——前者是客观需求,对谁都一样;后者是主观需求,因人而 异。

(1)列举所有的人员参与者 (2) 调查研究 (3)区分人员类型 (4) 统计(或估算)各类人员的比例 (5)了解使用者的主观需求 (6) 按照一定的准则进行折中与均衡

Page 66: 第七讲  面向对象设计

人机交互子系统 -2 描述用户 描述用户信息有:

用户类型。 使用系统欲达到的目的。 特征 ( 年龄、性别、受教育程度、限制因素等 ) 。 关键的成功因素 ( 需求、爱好、习惯等 ) 。 技能水平。 完成本职工作的脚本。

Page 67: 第七讲  面向对象设计

人机交互子系统 -3 设计命令层次 设计命令层次的工作通常包含以下内容:

1. 研究现有的人机交互 含义和准则2. 确定初始的命令层次3. 精化命令层次。应该考虑下列一些因素:

Page 68: 第七讲  面向对象设计

人机交互子系统 -3 设计命令层次 现在, Windows已经成为微机图 形用户界面事实上的工业标准。 所有 Windows应用程序的基本外观及给用户的感受都

是相同的。 Windows 程序通常还遵守广大用户习以为常的许多约定

。 设计图形用户界面时,应该保持与普通 Windows应用程序界面相一致,并遵守广大用户习惯的约定,这样才会被用户接受和喜爱。

Page 69: 第七讲  面向对象设计

人机交互子系统 -3 设计命令层次 所谓命令层次,实质上是用过程抽象机制组织

起来的、可供选用的服务的表示形式。 设计命令层次时,通常先从对服务的过程抽象着手,然后再进一步修改它们,以适合具体应用环境的需要。

Page 70: 第七讲  面向对象设计

人机交互子系统 -3 设计命令层次

为进一步修改完善初始的命令层次,应该考虑下列一些因素: 次序:仔细选择每个服务的名字,并在命令层的每一部

分内把服务排好次序。 整体 -部分关系:寻找在这些服务中存在的整体 -部分

模式,这样做有助于在命令层中分组组织服务。 宽度和深度:命令层次的宽度和深度都不应该过大。 操作步骤:应该用尽量少的单击、拖动和击键组合来表

达命令,而且应该为高级用户提供简捷的操作方法。

Page 71: 第七讲  面向对象设计

人机交互子系统 -4 设计人机交互类

人机交互类与所使用的操作系统及编程语言密切相关。

例如,在 Windows环境下运行的 Visual C++ 语言提供了MFC 类库,设计人机交互类时,往往仅需从 MFC 类库中选出一些适用的类,然后从这些类派生出符合自己需要的类就可以了。

Page 72: 第七讲  面向对象设计

人机 界面的设计准则

• 易学、易用、操作方便 • 尽量保持一致性 • 及时提供有意义的反馈 • 使用户的注意力集中在当前的任务上而不是界面上 • 尽量减少用户的记忆 • 具有语境敏感的帮助功能 • 减少重复的输入和操作 • 对用户的操作具有容错性 ,如 UNDO

• 防止灾难性的错误 • 其它:如艺术性、趣味性、风格、视感等

Page 73: 第七讲  面向对象设计

案例

Page 74: 第七讲  面向对象设计

界面类图—局部示例

Page 75: 第七讲  面向对象设计

7 任务管理子系统 任一“任务”都是由各个“对象”协同工作完成的,不

同的任务标识了必须同时发生的不同行为。所以任务管理时要特别考虑对象之间的协调,特别是那些需要并发工作的对象、存在相互依赖的对象:

因此,设计“任务管理子系统”时: 一项重要内容就是:确定哪些是必须同时动作的对象,哪些是

相互排斥的对象。 然后进一步设计任务管理子系统。

分为以下两步: 分析并发性 设计任务管理子系统

Page 76: 第七讲  面向对象设计

并发的含义

通过面向对象分析建立起来的动态模型,是分析并发性的主要依据。

如果两个对象彼此间不存在交互, 或者它们同时接受事件,则这两个对象在本质上是并发的。

Page 77: 第七讲  面向对象设计

控制线的含义 通过检查各个对象的状态图及它们之间交换的 事

件,能够把若干个非并发的对象归并到一条控制线中。

所谓控制线,是一条遍及状态图集合的路径,在这条路径上每次只有一个对象是活动的。

在计算机系统中用 任务 (task) 实现控制线,一般认为任务是进程 (process) 的别名。通常把多个任务的并发执行称为多任务。

Page 78: 第七讲  面向对象设计

任务与并发的关系 对于某些应用系统来说,通过划分任务,可以简化

系统的设计及编码工作。 不同的任务标识了必须同时发生的不同行为。 这种并发行为既可以在不同的处理器上实现,也可

以在单个处理器上利用多任务操作系统仿真实现 (通常采 23/4/20用时间分片策略仿真多处理器环境 ) 。

Page 79: 第七讲  面向对象设计

设计任务管理子系统常见的任务 事件驱动型任务 时钟驱动型任务 优先任务 关键任务 协调任务

Page 80: 第七讲  面向对象设计

设计任务管理子系统的工作内容 设计任务管理子系统,包括:

确定各类任务 把任务分配给适当的硬件或软件去执行

Page 81: 第七讲  面向对象设计

事件驱动型任务的意义

某些任务是由事件驱动的,这类任务可能主要完成通信工作。

例如,与设备、屏幕窗口、其他任务、子系统、另一个处理器或其他系统通信。

事件通常是表明某些数据到达的信 号。

Page 82: 第七讲  面向对象设计

事件驱动型任务的工作过程

在系统运行时,事件驱动型任务的工作过程如下: 任务处于睡眠状态 ( 不消耗处理器时间 ) ,等待来自数据线或其他数据 源的中断;

一旦接收到中断就唤醒了该任务:• 接收数据• 把数据 放入内存缓冲区或其他目的地• 通知需要知道这件事的对象

该任务又回到睡眠状态。

Page 83: 第七讲  面向对象设计

“ 时针驱动”的含义 某些任务每隔一定时间间隔就被触发以执行某

些处理。 例如:

某些设备需要周期性地获得数据 某些人机 接口、 子系统、任务、处理器或其他系统也可能需要周期性地通信

在这些场合往往需要使用时钟驱动型任务。

Page 84: 第七讲  面向对象设计

时钟驱动型任务的工作过程 时钟驱动型任务的工作过程如下:

任务设置了唤醒时间; 任务进入睡眠状态; 任务睡眠 ( 不消耗处理器时间 ) ,等待来自系统的中断

; 一旦接收到中断,任务就被唤醒并做它的工作:通知有

关对象; 任务又回到睡眠状态。

Page 85: 第七讲  面向对象设计

确定优先任务 优先任务可以满足高优先级或低优先级的处理需求

: 高优先级:

• 某些服务具有很高的优先级• 为了在严格限定的时间内完成这种服务,可能需要把

这类服务分离成独立的任务。 低优先级:

• 与高优先级相反,有些服务是低优先级的,属于低优先级处理 ( 通常指那些背景处理 ) 。

• 设计时可能用额外的任务把这样的处理分离出来。

Page 86: 第七讲  面向对象设计

确定关键任务 关键任务是有关系统成功或失败的关键处理,

这类处理通常都有严格的可靠性要求。 在设计过程中可能用额外的任务把这样的关键处理分离出来,以满足高可靠性处理的要求。

对高可靠性处理应该精心设计和编码,并且应该严格测试。

Page 87: 第七讲  面向对象设计

确定协调任务 当系统中存在 3 个以上任务时,就应该增加一个

任务,用它作为协调任务。 优劣:

引入协调任务会增加系统的总开销 ( 增加从一个任务到另一个任务的转换时间 )

引入协调任务有助于把不同任务之间的协调控制封装起来。

方法:使用状态转换矩阵可以比较方便地描述该任务的行为。

注意:这类任务应该仅做协调工作,不要让它再承担其他服务工作。

Page 88: 第七讲  面向对象设计

尽量减少任务数 必须仔细分析和选择每个确实需要的任务。应该

使系统中包含的任务数尽量少。 设计多任务系统的主要问题是:

设计者常常为了自己处理时的方便而轻率地定义过多的任务。

这样做加大了设计工作的技术复杂度,并使系统变得不易理解,从而加大了系统维护的难度。

Page 89: 第七讲  面向对象设计

估算 CPU 或其他固件的处理能力 使用多处理器 ( 即“多个处理器” ) 或固件,主要

是为了满足高性能的要求。 设计者必须通过计算系统载荷 ( 即每秒处理的业务

数及 处理一个业务所花费的时间 ) ,来估算所需要的 CPU(或其他固件 ) 的处理能力。

Page 90: 第七讲  面向对象设计

确定资源需求 设计者应该综合考虑各种因素,以决定哪些子系统用硬

件实现,哪些子系统用软件实现。 下面两个因素可能是使用硬件实现某些子系统的主要因素。 现有的硬件完全能满足某些方面的需求,例如,买一块浮点运算卡比用软件实现浮点运算要容易得多。

专用硬件比通用的 CPU 性能更高。例如,目前在信号处理系统中广泛使用固件实现快速傅里叶变换。

设计者在决定到底采用软件还是硬件的时候,必须综合权衡一致性、成本、性能等多种因素,还要考虑未来的可扩充性和可修改性。

Page 91: 第七讲  面向对象设计

8 设计数据管理子系统 数据管理 子系统是系统存储或检索对象的基本设施

,它: 建立在某种数据存 储管理系统之上 隔离了数据存 储管理模式 ( 文件、关系数据 库或面向对

象数据 库 ) 的影响

人机交互部分

控制流管理部分

问题域部分

数据管理部分

文件系统

数据管理部分

文件系统

数据管理部分

关系型 DBMS

数据管理部分

OO-DBMS

Page 92: 第七讲  面向对象设计

a 数据存储管理模式 不同的数据存 储管理模式有不同的特点,适用范

围也不相同,设计者应该根据应用系统的特点选择适用的模式: 文件管理系统 关系数据 库管理系统 面向对象数据 库管理系统

Page 93: 第七讲  面向对象设计

文件管理系统 文件管理系统是操作系统的一个组成部分,使用

它长期保存数据具有成本低和 简单等特点。 但是,文件操作的级别低,为提供适当的抽象级

别还必须编写额外的代码。 此外,不同操作系统的文件管理系统往往有明显差异。

Page 94: 第七讲  面向对象设计

关系数据库管理系统的主要优点

关系数据 库管理系统的理论基础是关系代数,它不仅理论基础坚实而且有下列一些主要优点:1. 提供了各种最基本的数据管理 功能 ( 例如,中断恢复,多用户共享,多应用共享,完整性,事务支持等 ) 。

2. 为多种应用提供了一致的接口。3. 标准化的语言 ( 大多数商品化关系数据 库管理系统都使用 SQL 语言 ) 。

Page 95: 第七讲  面向对象设计

关系数据库管理系统的缺点 关系数据 库管理系统有下述一些具体缺点:

1. 运行开销大:即使只完成简单的事务 ( 例如,只修改表中的一行 ) ,也需要较长的时间。

2. 不能满足高级应用的需求:关系数据 库管理系统很难用在数据类型 丰富或操作不标准的应用中。

3. 与程序设计语言的连接不自然: SQL 语言支持面向集合的操作,是一种非过程性语言;然而大多数程 序设计语言本质上却是过程性的,每次只能处理一个记录。

这些具体缺点限制了关系数据 库管理系统的普遍使用。

Page 96: 第七讲  面向对象设计

人员 -ID 人员姓名 地址 身份证号1 张三 海淀路 11号 2131251255 李四 清华西路 123号 12555125471 张三 天津海河路 2号 5626 4246

人员 -ID 祖籍1 山东5 云南71 浙江

元组、记录

属性、字段

候选关键字:可保证表的每个元组唯一性的任何属性的集合。

指定侯选关键字中的一个为表的主关键字主关键字。

外键:连接表的关键字。

满足一些范式

Page 97: 第七讲  面向对象设计

面向对象数据库管理系统 面向对象数据 库管理系统是一种新技术,主要有两种设计途径: 扩展的关系数据 库管理系统

• 在关系数据 库基础上,增加抽象数据类型和继承机 制;• 还增加了创建及管理类和对象的通用服务。

扩展的面向对象程序设计语言• 扩充了面向对象程序设计语言的语法和功能,增加了在

数据 库中存储和管理对象的机制。• 开发人员可以用统一的面向对象观点进行设计,不再需

要区分存储数据结构和程 序数据结构 ( 即生命期短暂的数据 ) 。

Page 98: 第七讲  面向对象设计

“ 对象”数据管理模式的实现 目前,大多数“对象”数据管理模式 都采用“复制对象”的方法: 先保留对象值,然后在需要时创建该对象的一个副本

。 扩展的 OO 程序设计语言则扩充了这种机制,它支持

“永久对象”方法:• 准确存储对象(包括对象的内部标识在内),而不

是仅仅存储对象值。• 使用这种方法,当从存储器中检索出一个对象的时候,它就完全等同于原先存在的那个对象。

• “永久对象”方法,为在多用户环境中从对象服务器中共享对象奠定了基础。

Page 99: 第七讲  面向对象设计

b 设计数据管理子系统的任务

设计数据管理 子系统,需要: 设计数据 格式 设计相应的服务。

Page 100: 第七讲  面向对象设计

设计数据格式 设计数据 格式的方法与使用的数据存 储管理模

式密切相关。 与前述数据存 储管理模式(文件管理系统、关

系数据 库管理系统、面向对象数据库管理系统)相对应的设计方法有:

1. 文件系统2. 关系数据 库管理系统3. 面向对象数据 库管理系统

Page 101: 第七讲  面向对象设计

设计数据格式——文件系统 设计文件系统的方法:

定义第一范式表:列出每个类的属性表;把属性表规范成第一范式,从而得到第一范式表的定义。

为每个第一范式表定义一个文件。 测量性能和需要的存储容量。 修改原设计的第一范式,以满足性能和存储需求。

必要时把泛化结构的属性压缩在单个文件中,以减少文件数量。

必要时把某些属性组合在一起,并用某种编码值表示这些属性,而不再分别使用独立的域表示每个属性。这样做可以减少所需要的存储空间,但是增加了处理时间。

Page 102: 第七讲  面向对象设计

设计数据格式——关系数据库管理系统

1 利用关系数据 库系统进行数据存 储设计

面向对象、实体 - 关系以及关系数据 库系统中的概念间的对应关系

面向对象 实体—联系 关系数据 库

类 实体类型 表对象 实体实例 行属性 属性 列关系 关系 表或与类的表在一起

Page 103: 第七讲  面向对象设计

22 、对象标识、对象标识 在程序运行时的对象标识是唯一的,对程序员来说

通常是不可以访问的,只是通过对象名来访问对象。

永久对象的标识在一个表中是唯一的。 由类导出的表用一个主关键字作为表中所存储的对

象的唯一标识。 由关联导出的表用相关联的表的主关键字组合作为

主关键字。 在应用中使用对象名,在表中使用主关键字。

Page 104: 第七讲  面向对象设计

3 、永久类的存储设计—— 每个永久类使用一个数据 库表

1 )确定要存储对象的哪些属性值,据此列出一个永久类的相应属性。 2 )按时间与空间要求进行权衡,对这些属性进行规范化,规范化后的属性至少应满足第一范式。 3 )定义数据 库的表

列:规范化之后的一个属性行:一个对象实例

把规范化之后类的一个属性作为表的一个列,要存储的每一个对象实例作为表中的一行。

若一个类的属性列表不满足第二范式或更高范式,有两种可选的策略:

( 1 ) 拆分类,这样要修改问题域模型;

( 2 )不修改类,而是让一个类对应两个或多个表,让每个表满足范式要求,这样在存储和检索类时要进行一定的转换运算。

Page 105: 第七讲  面向对象设计

105

4 、对关系的存储(1) 对关联的存储设计 在关系数据 库中按下述方法对关联进行数据存 放:

每个一对一的关联映射到一张独立的表;或在各类对应的表中用外键隐含;也可把两个对象和关联放在同一表中。

每个一对多的关联映射到一张独立的表;或在“多”的类对应的表中用外键隐含。

  每个多对多的关联映射到一张独立的表,该表的主关键字是两个进行关联的表的主关键字的拼接;或者把它转化为一对多的关联,然后再按一对多的方式进行处理。

Page 106: 第七讲  面向对象设计

106

将关联或聚合映射到表格将关联或聚合映射到表格

一对一关联雇员

雇员号码名字

办公室办公室名

地点

1 1

只映射到一个表

属性名 是否为空 域雇员号码 N 号码名字 N 名字办公室名 N 名字地点 N 地点 使用得较多,能提

高性能。

Page 107: 第七讲  面向对象设计

107

映射到多个表

属性名 是否为空 域雇员号码 N 号码名字 N 名字

属性名 是否为空 域办公室名 N 名字地点 N 地点

属性名 是否为空 域雇员号码 N 号码办公室名 N 名字

关联

Page 108: 第七讲  面向对象设计

108

一对多关联

公司公司名称

地址

人员人员姓名

地点

1..*1

属性名 是否为空 域公司 ID N 号码人员 ID N 号码

为关联单建一个表

Page 109: 第七讲  面向对象设计

109

属性名 是否为空 域人员 ID N 号码人员姓名 N 姓名地点 Y 地址公司 ID N 号码

在对象较多的类中建立表

Page 110: 第七讲  面向对象设计

110

多对多关联

1..*1..* 用户 工作站

工作站用户 使用权1 1..* 1..* 1

(2) 对聚合的存储设计 聚合聚合遵循与关联同样的规则

Page 111: 第七讲  面向对象设计

111

(3) 对泛化的存储设计可采用下述方法之一,进行数据存 放。

① 把一般类的各个子类的属性都集中到一般类中,创建一个表。

② 为一般类(非抽象类)创建一个表,并为它的各个特殊类各创建一个表。一般类的表与各子类的表要用同样的属性作为主关键字。

③ 如果一般类为抽象类,则要把一般类的属性放到各子类中,为它的子类各建立一张表。若一般类不为抽象类,也可采用 (2) 的做法。

上述是对单继承的处理方法,对于多继承的处理与此类似。

Page 112: 第七讲  面向对象设计

112

将泛化映射到表将泛化映射到表设备

设备名称价格

水泵吸气压力排气压力

热交换器表面面积

Page 113: 第七讲  面向对象设计

113

属性名 是否为空 域设备 ID N 号码设备名称 N 名称价格 Y 金额设备类型 N 设备类型

父类和子类各对应一张表父类和子类各对应一张表

属性名 是否为空 域设备 ID N 号码吸气压力 Y 压力排气压力 Y 压力

属性名 是否为空 域

设备 ID N 号码

表面面积 Y 面积

候选关键字:设备 ID ,设备名称

主关键字:设备 ID

常见访问:设备 ID ,设备名称

候选关键字:设备 ID

主关键字:设备 ID

常见访问:设备 ID

候选关键字:设备 ID

主关键字:设备 ID

常见访问:设备 ID

Page 114: 第七讲  面向对象设计

114

当从子类对应的表开始检索时 :

根据提供的设 备 ID, 用设备 ID查找子类相应表中的行,再在父类对应的表中,用设备 ID 和查找表中的行 , 即检索出该设备的所有信息。

当从父类对应的表开始检索时 :

根据提供的设 备 ID 和设备类型 , 用设备 ID查找父类相应表中的行,用设备类型确定查那个子类所对应的表 , 再在子类对应的表中,用设备 ID查找表中的行 , 即检索出该设备的所有信息。

Page 115: 第七讲  面向对象设计

115

每个子类各对应一张表每个子类各对应一张表

属性名 是否为空 域设备 ID N 号码设备名称 N 名称价格 Y 金额吸气压力 Y 压力排气压力 Y 压力

属性名 是否为空 域设备 ID N 号码设备名称 N 名称价格 Y 金额表面面积 Y 面积

候选关键字:设备 ID ,设备名称

主关键字:设备 ID

常见访问:设备 ID ,设备名称

候选关键字:设备 ID ,设备名称

主关键字:设备 ID

常见访问:设备 ID ,设备名称

Page 116: 第七讲  面向对象设计

116

属性名 是否为空 域设备 ID N 号码设备名称 N 名称价格 Y 金额设备类型 N 设备类型吸气压力 Y 压力排气压力 Y 压力表面面积 Y 面积

候选关键字:设备 ID ,设备名称

主关键字:设备 ID

常见访问:设备 ID ,设备名称

只父类对应一张表只父类对应一张表

Page 117: 第七讲  面向对象设计

117

( 1 )(下推)为每一个子类定义一个单独的表。这种方法简单,但存在一些问题,因为当增加新的子类或修改父类时,对数据 库的维护是麻烦的。

( 2 )(上拉)去掉继承的网格结构,使一个层次的任何一个类的所有实例都拥有相同的状态。这种方法的缺点是对许多实例要存储大量的冗余信息。

( 3 )(分割表)将父类和子类的状态存储在不同的表中。这种方法很好地反映了继承网格,但它的缺点是访问数据 时需要许多跨表连接。

Page 118: 第七讲  面向对象设计

118

5 、设计数据管理部分的类并修改问题域部分

—— 两种方案方案 1 : 每个类的对象自己存储、检索自己( 1 )告诉一个对象自己存储自己( 2 )每个对象知道如何保存自己( 3 )检索被存储的对象

为了存储自己,对象要知道什么?本类对象的属性数据结构本类对象对应哪个数据 库表如何找到对象在数据 库表中对应的位置

永久存储类

类名 - 数据 库表名

存储对象检索对象

注意:永久类的属性和操作是新增加的,该类原有的属性和操作仍然要保留。

Page 119: 第七讲  面向对象设计

119

方案 2 :数据管理部分设立一个对象, 负责问题域部分所有对象的存储与检索问题域部分的对象通过消息使用数据管理部分对象的操作( 1 )告诉一个对象存储自己( 2 )每个对象知道为了保存自己的状态,该传送什么消息到负责存储的对象;( 3 )检索被存储的对象

为了存储各个类的对象,“对象存储器”的对象要知道什么?

每个要求存储的类的属性数据结构每个要求存储的类的对象存放在哪个数据 库表当前要求检索的对象属于哪个类,如何找到它在数据库表中对应的位置。

对象存储器类名 - 数据 库表名对照表

存储对象检索对象

Page 120: 第七讲  面向对象设计

设计数据格式——面向对象数据库管理系统

设计面向对象数据 库管理系统方法: 扩展的关系数据 库途径:使用与关系数据 库管理系统相

同的方法。 扩展的面向对象程序设计语言途径:不需要规范化属性

的步骤,因为数据 库管理系统本身具有把对象值映射成存储值的功能。

Page 121: 第七讲  面向对象设计

如何存储对象 在一个需要存储的类中,增加一个特殊的属性和服

务,用于完成存储对象自身的工作。 应该把为此目的增加的属性和服务作为“隐含”的属性和服务,即: 无须在面向对象设计模型的属性和服务层中显式地表示

它们; 仅需在关于类与对象的文档中描述它们。

Page 122: 第七讲  面向对象设计

上述“存储对象”方法的好处 这样设计之后,对象将知道怎样存储自己。

用于“存储自己”的属性和服务,在问题域子系统和数据管理 子系统之间构成一座必要的桥梁。

利用多重继承机制,可以在某个适当的基类中定义这样的属性和服务,然后,如果某个类的对象需要长期存储,该类就从基类中继承这样的属性和服务。——这样可避免许多冗余。

Page 123: 第七讲  面向对象设计

例子 ATM 系统 -1

由图可见:惟一的永久性数据存 储放在分行计算机中。 因为必须保持数据的一致性和完整性,而且 常常有多个并发事务同时访问这些数据, 因此,采用成熟的商品化关系数据库管理系统存储数据。

应该把每个事务作为一个不可分割的批操作来处理,由事务封锁账户直到该事务结束为止。

Page 124: 第七讲  面向对象设计

例子 ATM 系统 -2

在这个例子中,需要存储的对象主要是账户类的对象。 账户类对象存储的两种方法

每个对象自己保存自己。帐户类对象在接到“存储自己”的通知后,知道怎样把自己存储起来 ( 需要增加一个属性和一个服务来定义上述行为 ) 。

由数据管理 子系统负责存储对象。• 帐户类对象在接到“存储自己”的通知后,知道怎样向数据管理 子系统发送什么消息,以便由数据管理 子系统把它的状态保存起来,为此也需要增加属性和服务来定义上述行为。

• 使用这种方法的优点,是无须修改问题域子系统。 应该定义一个数据管理类 ObjectServer ,并声明它的对

象。这个类提供下列服务: 通知对象保存自身或保存需长期存储的对象的状态。 检索已存储的对象并使之“复活”。

Page 125: 第七讲  面向对象设计

9 设计类中的服务 OOA 得到的对象模型,通常并不详细描述类中

的服务。 OOD 则是扩充、完善和细化面向对象分析模型

的过程,设计类中的服务是OOD 的一项重要工作内容。

设计类中的服务包括以下活动: 确定类中应有的服务 设计实现服务的方法

Page 126: 第七讲  面向对象设计

a 确定类中应有的服务 需要综合考虑对象模型、动态模型和功能模型,才能确定类中应有的服务。 对象模型是进行对象设计的基本框架。但是面向对象分

析得出的对象模型,通常只在每个类中列出几个最核心的服务。

设计者必须把动态模型中对象的行为以及功能模型中的数据 处理转换成由适当的类所提供的服务。

Page 127: 第七讲  面向对象设计

状态图 ( 或动态模型 ) 的作用 一张状态图描绘了一类对象的生命周期,图中的状态转换是执行对象服务的结果。 对象的许多服务都与对象接收到的事件密切相关

• 事实上,事件就表现为消息• 接收消息的对象必然有由消息选择符指定的服务,该服务改变对象状态 (修改相应的属性值 ),并完成对象应做的动作。

对象的动作既与事件有关,也与对象的状态有关。• 如果一个对象在不同状态可以接受同样事件,而且

在不同状态接收到同样事件时其行为不同,则实现服务的算法中需要有一个依赖于状态的 DO_CASE型控制结构。

Page 128: 第七讲  面向对象设计

功能模型的作用 功能模型中的数据 处理,转换成由适当的类所提供

的服务。 功能模型指明了系统必须提供的服务。 状态图中状态转换所触发的动作,在功能模型中有时可能扩展成一张数据 流图。

Page 129: 第七讲  面向对象设计

功能模型的作用 数据 流图中的某些处理可能与对象提供的服务相对应,应该在该对象所属的类中定义这个服务——下列规则有助于确定这种定义: 如果某个处理的功能是从输入流中抽取一个值,则该输入流就是目标对象。

如果某个处理具有类型相同的输入流和输出流,而且输出流实质上是输入流的另一个形式,则该输入输出流就是目标对象。

如果某个处理从多个输入流得出输出值,则该处理是输出类中定义的一个服务。

如果某个处理把对输入流处理的结果输出给数据存 储或动作对象,则该数据存 储或动作对象就是目标对象。

Page 130: 第七讲  面向对象设计

如何确定处理的归属 当一个处理涉及多个对象时,为确定把它作为哪个

对象的服务,设计者必须判断哪个对象在这个处理中起主要作用。通常在起主要作用的对象类中定义这个服务。

下面两条规则有助于确定处理的归属: 如果处理影响或修改了一个对象,则最好把该处理与处

理的目标(而不是触发者)联系在一起。 考察处理涉及的对象类及这些类之间的关联,从中找出处于中心地位的类。如果其他类和关联围绕这个中心类构成星型,则这个中心类就是处理的目标。

Page 131: 第七讲  面向对象设计

b 设计实现服务的方法

1. 设计实现服务的算法时,应该考虑下列几个因素:① 算法复杂度。 通常选用复杂度较低 (即效率较高 )的算法,但也不要过分追求高效率,应以能满足用户需求为准。

② 容易理解与容易实现。容易理解与容易实现的要求往往与高效率有矛盾,设计者应该对这两个因素适当折衷。

③ 易修改。应该尽可能预测将来可能做的修改,并在设计时预先做些准备。

Page 132: 第七讲  面向对象设计

2. 选择数据结构 在分析阶段,仅需考虑系统中需要的信息的逻辑结构; 在OOD 过程中,需要选择能够方便、有效地实现算法

的物理数据结构。3. 定义内部类和内部操作

在OOD 过程中,可能需要新增加一些在需求陈述中没有提到的类,这些新类主要用来存放在执行算法过程中所得出的某些中间结果。

复杂操作往往可以用简单对象上的更低层操作来定义。因此,在分解高层操作时常常引入新的低层操作。在面向对象设计过程中应该定义这些新增加的低层操作。

Page 133: 第七讲  面向对象设计

10 设计关联 在对象模型中,关联是联结不同对象的纽带,它指

定了对象相互间的 访问路径。 在OOD 过程中,设计人员必须确定实现关联的具体策

略。 既可选定一个全局性的策略统一实现所有关联,也可以

分别为每个关联选择具体的实现策略,以与它在应用系统中的使用方式相适应。

为了更好地设计实现关联的途径,首先应该分析使用关联的方式。

Page 134: 第七讲  面向对象设计

设计关联中要讨论的内容 关联的遍历 实现单向关联 实现双向关联 关联对象的实现

Page 135: 第七讲  面向对象设计

设计关联之一:关联的遍历 在应用系统中,使用关联有两种可能的方式:

单向遍历。某些关联只需要单向遍历,这种单向遍历实现起来比较简单。

双向遍历。某些关联可能需要双向遍历,双向关联实现起来稍微麻烦一些。

在使用原型法开发软件的时候,原型中所有关联都应该是双向的,以便于增加新的行为,快速地扩充和修改原型。

Page 136: 第七讲  面向对象设计

设计关联之二:实现单向关联 用指针可以方便地实现单向关联。

如果关联的重数是一 元的,则实现关联的指针是一个简单指针;

如果重数是多元的,则需要用一个指针集合实现关联。

Page 137: 第七讲  面向对象设计

设计关联之三:实现双向关联 实现双向关联有下列 3 种方法:

只用属性实现一个方向的关联,当需要反向遍历时就执行一次正向查找。如果两个方向遍历的频度相差很大,而且需要尽量减少存储开销和修改时的开销,则这是一种很有效的实现双向关联的方法。

两个方向的关联都用属性实现。这种方法能实现快速访问,但是,如果修改了一个属性,则相关的属性也必须随之修改,才能保持该关联链的一致性。

用独立的关联对象实现双向关联。关联对象不属于相互关联的任何一个类,它是独立的关联类的实例,如图所示。

Page 138: 第七讲  面向对象设计

设计关联之四:关联对象的实现 可以引入一个关联类来保存描述关联性质的信息,关联中的

每个连接对应着关联类的一个对象。 实现关联对象的方法取决于关联的重数。

对于一对一关联来说,关联对象可以与参与关联的任一个对象合并。

对于一对多关联来说,关联对象可以与“多”端对象合并。 如果是多对多关联,则关联链的性质不可能只与一个参与关联的对

象有关,通常用一个独立的关联类来保存描述关联性质的信息,这个类的每个实例表示一条具体的关联链及该链的属性。

Page 139: 第七讲  面向对象设计

11“ 设计优化”

确定优先级提高效率的几项技术调整继承关系

Page 140: 第七讲  面向对象设计

a 确定优先级 系统的各项质量指标并不是同等重要的,设计人员必须确定各项质量指标的相对重要性 ( 即确定优先级 ) ,以便在优化设计时制定折衷方案。

系统的整体质量与设计人员所制定的折衷方案密切相关。 最终产品成功与否,在很大程度上取决于是否选择好了系统目标。

最糟糕的情况是,没有站在全局高度正确确定各项质量指标的优先级,以致系统中各个子系统按照相互对立的目标做了优化,这将导致系统资源的严重浪费。

Page 141: 第七讲  面向对象设计

在效率和清晰性之间寻求适当的折衷方案

在折衷方案中设置的优先级应该是模糊的。事实上,不可能指定精确的优先级数值,如: 速度 48% 内存 25% 费用 8% 可修改性 19%

最常见的情况,是在效率和清晰性之间寻求适当的折衷方案。

Page 142: 第七讲  面向对象设计

b 提高效率的几项技术 提高效率有 3 项技术:

增加冗余关联以提高访问效率 调整查询次序 保留派生属性

Page 143: 第七讲  面向对象设计

① 为什么增加冗余关联? 在OOA 过程中,应该避免在对象模型中存在冗余

的关联,因为冗余关联不仅没有增添任何信息,反而会降低模型的清晰程度。

但是,在面向对象设计过程中,当考虑用户的访问模式,及不同类型的访问彼此间的依赖关系时,就会发现,分析阶段确定的关联可能并没有构成效率最高的访问路径。

Page 144: 第七讲  面向对象设计

例子:分析访问路径、提高访问效率

下面用设计公司雇员技能数据 库的例子,说明分析访问路径及提高访问效率的方法。

下图是从面向对象分析模型中摘取的一部分。 公司类中的服务 find_skill返回具有指定技能的雇员集合。例

如,用户可能询问公司中会讲日语的雇员有哪些人。 假设某公司共有 2000名雇员,平均每名雇员会 10种技能,则简单的嵌套查询将遍历雇员对象 2000次,针对每名雇员平均再遍历技能对象 10次。如果全公司仅有 5 名雇员精通日语,则查询命中率仅有 1/4000 。

Page 145: 第七讲  面向对象设计

例子:使用哈希 (Hash) 表提高效率 提高访问效率的一种方法是使用哈希 (Hash) 表

:“具有技能”这个关联不再利用无序表实现,而是改用哈希表实现。

只要“会讲日语”是用惟一一个技能对象表示,这样改进后就会使查询次数由 20000次减少到2000次。

Page 146: 第七讲  面向对象设计

例子:为对象建立索引以提高查询效率

当仅有极少数对象满足 查询条件时,使用哈希 (Hash) 表查询的命中率仍然很低。在这种情况下,更有效的提高查询效率的改进方法是,给那些需要经常查询的对象建立索引。

例如,针对上述例子,可以增加一个额外的限定关联“精通语言”,用来联系公司与雇员这两类对象,如图所示。

利用适当的冗余关联,可以立即查到精通某种具体语言的雇员,而无须多余的访问。

索引必然带来开销:占用内存空间,而且每当修改基关联时也必须相应地修改索引。因此,通常只给那些经常执行并且开销大、命中率低的查询建立索引。

Page 147: 第七讲  面向对象设计

② 调整查询次序

优化算法的一个途径是尽量缩小查找范围。 例如,假设用户在使用上述的雇员技能数据 库

的过程中,希望找出既会讲日语又会讲法语的所有雇员。如果某公司只有 5 位雇员会讲日语,会讲法语的雇员却有 200 人,则 应该先查找会讲日语的雇员,然后再从这些会讲日语的雇员中查找同时又会讲法语的人。

Page 148: 第七讲  面向对象设计

③ 保留派生属性 通过某种运算而从其他数据 派生出来的数据,

是一种冗余数据。通 常把这类数据 “存储” ( 或称为“隐藏” ) 在计算它的表达式中。如果希望避免重复计算复杂表达式所带来的开销,可以把这类冗余数据作为 派生属性保存起来。

派生属性既可以在原有类中定义,也可以定义新类,并用新类的对象保存它们。每当修改了基本对象之后,所有依赖于它的、保存派生属性的对象也必须相应地修改。

Page 149: 第七讲  面向对象设计

调整继承关系 在面向对象设计过程中,建立良好的继承关系是优

化设计的一项重要内容。 继承关系能够为一个类族定义一个协议,并能在类

之间实现代码共享以减少冗余。 一个基类和它的子孙类在一起称为一个类继承。 利用类继承能够把若干个类组织成一个逻辑结构。

Page 150: 第七讲  面向对象设计

与建立类继承有关的问题 抽象与具体 为提高继承程度而修改类定义 利用委托实现行为共享

Page 151: 第七讲  面向对象设计

抽象与具体 在设计类继承时,很少使用纯粹自顶向下的方法

。 通常的作法是,首先创建一些满足具体用途的类

,然后对它们进行归纳,一旦归纳出一些通用的类以后,往往可以根据需要 再派生出具体类。在进行了一些具体化 ( 即专门化 ) 的工作之后,也许就应该再次归纳了。对于某些类继承来说,这是一个持续不断的演化过程。

Page 152: 第七讲  面向对象设计

23/4/20 152

抽象与具体的例子 如图用一个人们在 日常生活中熟悉的例子,说明从具体到抽象

,再到具体的过程:

Page 153: 第七讲  面向对象设计

与建立类继承有关的问题 抽象与具体 为提高继承程度而修改类定义 利用委托实现行为共享

Page 154: 第七讲  面向对象设计

从一组相似类中归纳出“一般类”

如果在一组相似的类中存在公共的属性和公共的行为,则可以把这些公共的属性和行为抽取出来放在一个共同的祖先类中,供其子类继承,如图所示:

为提高继承程度而修改类定义

Page 155: 第七讲  面向对象设计

归纳现有类时注意的问题 在对现有类进行归纳的时候,要注意下述两点:

不能违背领域知识和常识; 应该确保现有类的协议 ( 即同外部世界的接口 ) 不变。

更常见的情况是,各个现有类中的属性和行为 ( 操作 ) ,虽然相似却并不完全相同,在这种情况下需要对类的定义稍加修改,才能定义一个基类供其子类从中继承需要的属性或行为。

有时抽象出一个基类之后,在系统中暂时只有一个子类能从它继承属性和行为,显然,在当前情况下抽象出这个基类并没有获得共享的好处。但是,这样做通常仍然是值得的,因为将来可能重用这个基类。

Page 156: 第七讲  面向对象设计

利用继承实现操作共享的问题 仅当存在真实的一般 -特殊关系 ( 即子类确实是父类的一种特殊形式 ) 时,利用继承机制实现行为共享才是合理的。

有时程序员只想用继承作为实现操作共享的一种手段,并不打算确保基类和派生类具有相同的行为。 在这种情况下,如果从基类继承的操作中包含了子类不应有的行为,则可能引起麻烦。

例如,假设程序员正在实现一个 Stack(后进先出栈 ) 类,类库中已经有一个 List(表 ) 类。如果程序员从 List 类派生出 Stack 类,则如图(a) 所示:• 把一个元素压入栈,等价于在表尾加入一个元素;• 把一个元素弹出栈,相当于从表尾移走一个元素。

但是,与此同时,也继承了一些不需要的表操作。例如,从表头移走一个元素或在表头增加一个元素。万一用户错误地使用了这类操作, Stack类将不能正常工作。

Page 157: 第七讲  面向对象设计

利用委托实现行为共享 如果只想把继承作为实现操作共享的一种手段,

则利用委托 ( 即把一类对象作为另一类对象的属性,从而在两类对象间建立组合关系 ) 也可以达到同样目的,而且这种方法更安全。

使用委托机制时,只有有意义的操作才委托另一类对象实现,因此,不会发生不慎继承了无意义( 甚至有害 ) 操作的问题。

图 (b) 描绘了委托 List 类实现 Stack 类操作的方法。 Stack 类的每个实例都包含一个私有的List 类实例 ( 或指向 List 类实例的指针 ) 。 Stack 对象的操作 push(压栈 ) ,委托List 类对象通过调用 last( 定位到表尾 ) 和add( 加入一个元素 ) 操作实现,而 pop(出栈 ) 操作则通过 List的 last和 remove(移走一个元素 ) 操作实现。

Page 158: 第七讲  面向对象设计

小结 1

面向对象设计就是用面向对象观点建立求解空间模型的过程。

优秀设计是使得目标系统在其整个生命周期中总开销最小的设计,为获得优秀的设计结果,应该遵循一些基本准则。

重用是提高软件生产率和目标系统质量的重要途径,它基本上始于设计。

Page 159: 第七讲  面向对象设计

小结 2

用面向对象方法设计软件,原则上也是先进行总体设计(即系统设计),然后再进行详细设计(对象设计),当然,它们之间的界线非常模糊,事实上是一个多次反复迭代的过程。

大多数求解 空间模型,在逻辑上由 4 大部分组成:问题域子系统、人机交互 子系统、任务管理子系统、数据管理 子系统。

通过应该在设计工作开始之前,对系统的各项质量指标的相对重要性做认真分析和仔细权衡,制定出恰当的系统目标。

Page 160: 第七讲  面向对象设计

作业

采用面向对象设计系统撰写系统设计说明书