? 面向对象的概念
? 面向对象的开发过程
? 面向对象分析与模型化
? 面向对象设计
? 面向对象程序的实现与测试
面向对象的概念
? 开发模式
? 什么是面向对象
? 对象
? 类
? 继承
开发模式 ( Paradigm)
? 开发模式又称为范型、范例、风范
或模式 (Pattern)。开发模式定义了
?特定问题和应用的开发过程中将
遵循的 步骤 ;
?确定将用于表示问题和解的那些
成分的 类型 ;
?利用这些成分表示与问题解决有
关的 抽象 ;
?直接得到问题的 结构 。
? 开发模式的选择影响到整个软件开
发生存期 。就是说,它支配了
?设计方法
?编码语言
?测试和检验技术
的选择
面向过程开发模式
? 面向过程开发模式产生 过程的抽象 。
? 这些抽象的基础是 把软件视为处理流,
并 定义成由一系列步骤构成的算法 。
? 每一步骤都是带有预定输入和特定输
出的一个过程,把这些步骤串联在一
起可 产生合理的稳定的贯通于整个程
序的控制流,最终产生一个简单的具
有静态结构的体系结构。
面向过程开发模式的特点
? 过程性开发模式 侧重建立构成问题解
决的处理流 。
? 数据抽象、数据结构 根据算法步骤的
要求开发,它贯穿于过程,提供过程
所要求操作的信息。
? 系统的状态是一组全局变量,这组全
局变量保存状态的值,把它们从一个
过程传送到另一个过程。
⑴ Initialize system;
⑵ Create and draw interface;
while QUIT not selected do
case
Mouse event,
create shape structure;
read mouse movements for data;
store newly created shape on list
of shape records;
KeyPress event:
if key = 'q' then exit loop;
else ignore;
Ecpose event:
refresh display by drawing each
shape structure;
⑷ Shut down system;
面向对象开发模式
? 在面向过程开发模式中优先考虑的
是 过程抽象,在面向对象开发模式
中优先考虑的是 实体(问题论域的
对象) 。
? 在面向对象开发模式中,把标识和
模型化 问题论域中的主要实体 做为
系统开发的起点,主要考虑对象的
行为而不是必须执行的一系列动作 。
面向对象开发模式的特点
? 面向对象系统中的 对象是数据抽象
与过程抽象的综合 。
? 系统的状态 保存在各个数据抽象的
所定义的数据存储中。
? 控制流 包含在各个数据抽象中的操
作内。
? 在面向对象体系结构。消息从一个
对象传送到另一个对象。 算法 被分
布到各种实体中。
其它流行的开发模式
? 目前流行多种开发模式,它们提供了许多方法,可进行系统分解。
? 面向过程的 ;
? 逻辑的 ;
? 面向存取的 ;
? 面向进程的 ;
? 面向对象的 ;
? 函数型的 ;
? 说明性的 。
? 每个开发模式都有它的支持者和用
户;
? 每个开发模式都特别适合于某种类
型的问题或子问题;
? 每一个开发模式都用不同的方式考
虑问题;
? 每一个开发模式都使用不同的方法
来分解问题;
? 每一个开发模式都导致不同种类的
块、过程、产生规则。
混合开发模式
? 在大型系统的开发中,很难说哪种
开发模式对整个问题的解决最好。
? 系统开发时,通常把 大型问题分解
成一组子问题 。 对于每个子问题可
以采用适当的软件开发模式 。
? 这种设计 需要有某种实现语言或一
组协同语言的支持 。许多流行的功
能不断增强的语言可支持不只一种
设计开发模式。
? 一个智能数据分析系统的设计,可
把它看做是 4 个子系统。系统有
? 一个 数据库界面,可以 使用面向存
取的方法 进行设计;
? 智能数据分析 用 逻辑性的开发模式
设计;
? 一组 分析算法 是 过程性的 ;
? 用户界面 是用 面向对象开发模式 设
计出来的。
什么是面向对象
? Coad和 Yourdon给出了一个定义:
,面向对象 =对象 +类 +继承 +通信,。
? 如果一个软件系统是使用这样 4 个
概念设计和实现的,则我们认为这
个软件系统是面向对象的。
? 一个面向对象的程序的每一成份应
是 对象,计算是通过 新的对象的建
立 和 对象之间的通信 来执行的。
对象 ( object )
? 对象 是面向对象开发模式的 基本成
份 。
? 每个对象可用 它本身的一组属性 和
它可以执行的一组操作 来定义。
? 属性 一般只能 通过执行对象的操作
来改变 。
? 操作 又称为方法或服务,它 描述了
对象执行的功能,若通过消息传递,
还可以为其它对象使用。
消息 ( Message )
? 消息是一个对象与另一个对象的通
信单元,是要求某个对象执行类中
定义的某个操作的规格说明。 发送
给一个对象的消息定义了一个 方法
名 和一个 参数表 (可能是空的),
并 指定某一个 对象 。
? 一个对象接收的消息则调用消息中
指定的 方法,并将 形式参数与参数
表中相应的值结合起来 。
类 (class)
? 类是一组具有 相同数据结构 和 相同
操作 的对象的集合。
? 类的定义包括 一组数据属性 和 在数
据上的一组合法操作 。
? 类定义可以视为一个具有类似特性
与共同行为的对象的 模板,可用来
产生对象。
? 在一个类中,每个 对象 都是 类的实
例 (Instance),它们都可使用类中
提供的函数。
? 对象的状态则包含在它的实例变量,
即实例的属性中。
类 ← 两个四边形对象
? Quadrilateral类的每个对象有同样的
一组实例变量和方法。
? 就这个意义来讲,类 Quadrilateral给
我们提供了一个模板,表示了所有
四边形对象。
? 类常常可看做是一个 抽象数据类型
(ADT)的实现。但更合适的是把类看
做是某种 概念的模型 。
? 类的实现常常使用其它类的实例,
它们提供了该类所需要的服务 。
? 这些实例应当受到保护不被其它对
象存取, 包括同一个类的其它实例 。
? 在四边形的例子中, 定义 4个 point
类的实例作为 Quadrilateral类的实
例的 4个顶点 。 这些 point对象不能
被其它对象存取 。
继承 (Inheritance)
? 继承 是 使用已存在的定义做为基础
建立新定义 的技术 。
? 新类的定义可以是 既存类所声明的
数据 和 新类所增加的声明 的组合 。
新类复用既存的定义, 而 不要求修
改既存类 。
? 既存类 可当做 基类 来引用, 则 新类
相应地可当做 派生类 来引用 。
? 使用继承设计一个新类, 可以视为
描述一个新的对象集, 它是既存类
所描述对象集的子集合 。
? 这个新的子集合可以认为是 既存类
的一个特殊化 。 Quadrilateral类是
Polygon类的特殊化 。 Quadrilateral
是限制为四条边的多边形 。 我们还
可以进一步地把类 Quadrilateral特
殊化为 Rectangle 。
? 类 Quadrilateral的界面可以等同于类
Polygon的界面, 而 Rectangle类的界
面又与 Quadrilateral类的界面相同 。
? 新类的界面还可以被看做是既存类界
面的一个 扩充界面 。 例如, 从一个既
存的 车辆 类派生的 四轮驱动车 类可能
不仅是 车辆 类子集合定义的特殊化,
而且还可能在新类的界面中引入新的
能力 。
类的继承层次
? 在类的继承层次中, Quadrilateral
的实际参数可以替换 Polygon的形式
参数 。
? 类 Quadrilateral的界面与类 Polygon
的界面是相容的
? Quadrilateral的界面可响应 Polygon
界面的所有消息 。
面向对象方法的开发过程
? 面向对象方法改进了在生存期各
个阶段之间的接口, 因为在生存
期各个阶段所开发出来的, 部件,
都是 类 。
? 在面向对象生存期的各个阶段对
各个类的信息进行细化, 类成为
分析, 设计和实现的 基本单元 。








复用 (Reusable)
? 在软件开发中, 复用扮演了重要
角色 。 软件部件应当独立于当初
开发它们的应用而存在 。
? 部件的开发瞄准某些局部的设计
和实现, 它们能够帮助当前问题
的解决, 但为了在以后的项目中
使用, 它们还应当 足够通用 。
? 类就是一个希望能够复用的单元,
因此,提出了一个,类生存期” 。
? 类生存期是与应用生存期是交叉的。
即就是说,类的标识是应用生存期
的一个阶段,但类生存期的步骤独
立于任一特殊应用的开发。
? 类的开发应能 完整地描述 一个基本
实体。而不仅仅考虑当前正在开发
的系统。
类的定义
? 一旦标识了一个类,就给出了它的
规格说明,其中包括 类的实例可执
行的操作 和 它们的数据表示 。
? 对每一个,无论是在哪一个阶段标
识的类都是如此。
? 对于那些使应用与数据库交互的类
来说,其规格说明应当包括 查找数
据库 和 向数据库加入数据的行为 。
? 类的规格说明定义了施加于对象的数
据存储上的 一组操作 。
? 这组操作应工作在封装在对象内部的
数据存储上,或返回关于对象状态的
信息。
? 操作的名字应能反映这个操作本身的
含义。
类的设计与实现
? 类的规格说明可指导对存放既存类的
软件库进行查找,这些既存类可用来
提供为当前应用所需要的功能。
? 三个可能的利用既存类的方向。开发
过程可能依赖于这种查找的结果。
?既存类的复用
? 从既存类进行演化
? 从废弃型进行开发
实现
? 通过 变量的声明, 操作界面的实现 及
支持界面操作的函数的实现,可实现
一个类的预期行为和状态。
? 实现是与语言有关的。一个好的面向
对象语言应当分离共有界面与其内部
实现。
? 采取必要措施分别编译界面和内部表
示。
测试
? 单个的类为测试提供了自然的单元。
? 如果类的定义提供的界面比较狭窄,
那么穷举测试就有可能实现。
? 类的测试在 最抽象的层次开始, 沿继
承关系继续向下进行 。
? 已经测试过的部分不需要从新测试。
? 重点放在 对新类的测试 和 组装测试 。
求精和维护
? 这是一个在软件生存期中最花费时间
的部分 。
? 传统的维护活动是针对应用的, 而 求
精过程是针对类, 针对把类集成在一
起的结构 。
? 我们可以标识抽象的抽象, 使得继承
结构通过一般化增加新的层次, 即在
既存的根类之上增加新的层次 。
概念的封装和实现的隐蔽
? 概念的封装和实现的隐蔽, 使得类
具有更大的独立性。 在任一时刻都
可以在类的界面上增加新的操作,
并能够修改实现,以改进性能,或
引入原来设计中没有的新服务。
? 为便于类的调整,应尽量做到定义
与实现分离 。对一个类的共有界面
的实现所做的多次修改不应影响利
用它的那些类。
面向对象分析与模型化
? 面向对象分析是软件开发过程中的
问题定义 阶段。
? 这一阶段最后得到的是对 问题论域
的 清晰, 精确 的定义。
? 分析阶段包括两个步骤,论域分析
和 应用分析 。
? 它们都要标识问题论域中的抽象。
? 在分析中, 需要
? 找到特定对象
? 基于对象的公共特性组合它们
? 标识出对这个问题的抽象
? 在分析阶段中要标识
? 抽象之间的关系
? 这些关系在应用系统中常常用对象
之间的消息来表示, 叫做 消息连接 。
? 在一个面向对象的应用中的控制流
由两部分构成:
? 每个单独操作内部的控制流
? 对象之间的消息模式
? 面向对象分析过程分两阶段:
?论域分析
?应用分析
论域分析
? 论域分析开发 问题论域的模型
? 考察问题论域内的一个较宽的
范围,分析覆盖的范围应比直
接要解决的问题更多 。
? 建立大致的系统实现环境
应用分析
? 应用分析则根据 特定应用的需
求 进行论域分析。
? 应用 (或系统 )分析细化在论域
分析阶段所开发出来的信息,
把 注意力集中于当前要解决的
问题 。
语义数据模型
? 语义数据模型 是一种特别适用的
建立 构成问题论域模型 的技术。
? 它基于 实体 —关系模型,并对这
类模型进行了扩充和一般化。语
义数据模型可以 表达问题论域的
内涵,还可以 表示复杂的对象和
对象之间的关系 。
语义数据模型与面向对象方法
语义
数据模型
主要特征
面向对象
分析与设计
外部模型 数据的
用户视图
与应用有关的
类的定义
概念模型 实体及实体之
间关系的内涵
类与类之间的
应用级关系
物理模型 数据的物理表示 类的实现
? 外部模型层反映 应用的外部现实世
界的视图, 它体现了用户对问题的
理解 。
? 概念模型层考虑 在外部模型层所标
识的实体之间的关系 。 这些关系都
是可直接观察到的交互关系 。
? 内部模型层考虑 实体的物理模型,
就是我们生存期中的类设计阶段 。
物理模型包括的属性
? 物理模型包括两类属性:
? 方法,对实体的行为模型化
? 数据,对实体的状态模型化
? 在模型中方法分为两种:
? 共有的
? 私有的
? 在分析阶段标识的属性是描述性的,
在语义数据模型中的关系
? 一般化和特殊化关系 可用来按层次渐
增式地定义抽象 (类 )。
? 低层抽象是高层抽象的特殊化。
? 这种抽象层次构成论域模型的基础。
? 例如,小汽车, 卡车 和 公共汽车 可以
归于更一般的概念 汽车 中。从这个较
一般化的概念 汽车 可以定义其它较特
殊的抽象,赛车, 面包车 和 牵引车 。
? 聚合关系 支持使用几个其它较小和
较简单的抽象来开发一个抽象。
? 它相应于一个记录中成份的声明。
? 例如,一个 航班 可以有 6个属性:
飞机编号、机组编号、离开和到达
地点、起飞和降落时间。因此,航
班 类有一个聚合关系,它利用了表
示 飞机, 人员, 空间 的类,并增加
了时间窗口。
? 关联关系 指定一个抽象做为其它抽
象实例的 包容 (container)。
? 关联和聚合之间的差别在于组合实
体的意图。 聚合指定一组实体中的
某些元素做为一个类的组成,而 关
联是指群集的相互有关联的实体群 。
? 例如,一个 部门 包含有 人,这样一
个 部门 关联了所有被分配给这个部
门的 人 。,这些 人 在系统其它地方
也可能出现。
对象模型化技术 OMT
? 对象模型化技术把分析时收集的信
息构造在三类模型中,即 对象模型,
功能模型 和 动态模型 。
? 这个模型化的过程是一个迭代过程。
对象模型
? 是三个模型中最关键的一个模型,
它的作用是 描述系统的静态结构,
包括 构成系统的类和对象, 它们的
属性和操作, 及 它们之间的关系 。
? 在 OMT中, 类与类之间的关系叫做
关联 。 关联代表一组存在于两个或
多个对象之间的, 具有相同结构和
含义的具体连接 。 关联可以是物理
的, 也可以是逻辑的 。
? 聚合,代表整体与部分的关系,这
是一种特殊形式的关联。
? 限定,用以对关联的含义做某种约
束。
? 角色,用来说明关联的一端。由于
多数关联具有两个端点,因而涉及
到两个角色。
? 附加的说明对象之间的连接的 连接
属性 。
一般化关系
? 也称为继承性。一般化关系包含基
类和几个派生类。
? 基类表示了一个较为一般、普遍的
概念
? 每个派生类则是它的某个特殊形态
? 派生类除了自然地继承基类所具有
的属性和操作外,还具有反映自身
特点的属性和操作。
动态模型
? 要想对一个系统了解得比较清楚,
还应当考察 在任何时刻对象及其
关系的改变 。
? 系统的这些涉及 时序 和 改变状况
用动态模型来描述 。
? 动态模型着重于 系统的控制逻辑 。
? 它包括两个图, 一是 状态图, 一
是 事件追踪图 。
状态图
? 状态图是一个 状态 和 事件 的网络,
侧重于 描述每一类对象的动态行为 。
? 在状态图中, 状态是对某一时刻中
属性特征的概括 。 而 状态迁移表示
这一类对象在何时对系统内外发生
的哪些事件做出何种响应 。
? 操作 是一个伴随状态迁移的瞬时发生
的行为,与触发事件一起表示在有关
的状态迁移之上。
? 活动 则是发生在某个状态中的行为,
往往需要一定的时间来完成,因此与
状态名一起出现在有关的状态之中。
? 动态模型由多个状态图组成。
? 对于 每一个具有重要动态行为的类
都有一个状态图,从而表明所有系
统活动的模式。
? 各个状态图并发地执行,并可以独
立地改变状态。
? 各种类的状态图可以通过共享事件
组合到一个动态模型中 。
事件
? 一个事件发生在某一时刻
? 每个事件都是单独发生的
? 我们建立事件类, 并给每个事件
一个名字, 以指明共同结构和行
为 。
? 事件从一个对象向另一个对象传
送信息 。
? 有些事件类可能传送的是简单的信
号“要发生某件事”,而有些事件
类则可能传送的是数据值。由事件
传送的数据值叫做属性。
? 列车出发 (线路、班次、城市 )
? 揿下鼠标按钮 (按钮、位臵 )
? 拿起电话受话器
? 数字拨号 (数字 )
事件追踪图
? 事件追踪图侧重于说明发生于系统
执行过程中的一个特定“场景” 。
? 场景 也叫做脚本,是完成 系统某个
功能的一个事件序列 。
? 场景通常 起始于一个系统外部的输
入事件, 结束于一个系统外部的输
出事件,它可以 包括发生在这个期
间的系统所有的内部事件 。
打打 电电 话话 者者 拿拿 起起 电电 话话 受受 话话 器器
电电 话话 忙忙 音音 开开 始始
打打 电电 话话 者者 拨拨 数数 字字 (8)
电电 话话 忙忙 音音 结结 束束
打打 电电 话话 者者 拨拨 数数 字字 (2),......
打打 电电 话话 者者 拨拨 数数 字字 (3)
接接 电电 话话 者者 的的 电电 话话 开开 始始 振振 铃铃
铃铃 声声 在在 打打 电电 话话 者者 的的 电电 话话 上上 传传 出出
接接 电电 话话 者者 回回 答答
接接 电电 话话 者者 的的 电电 话话 停停 止止 振振 铃铃
铃铃 声声 在在 打打 电电 话话 者者 的的 电电 话话 中中 消消 失失
通通 电电 话话,........
状态图与事件追踪图的关系
? 状态图叙述一个对象的个体行为,
事件追踪图则给出多个对象所表现
出来的集体行为 。它们从不同侧面
来说明同一系统的行为。
? 例如,一个事件追踪图指出某一对
象在接受一个事件之后发出另一事
件,同一行为在此对象的状态图中
也应当有所表示。
功能模型
? 功能模型表明, 通过计算, 从输
入数据能得到什么样的输出数据,
不考虑参加计算的数据按什么时
序执行 。
? 功能模型 由多个数据流图组成,
它们指明从外部输入, 通过操作
和内部存储, 直到外部输出, 这
整个的数据流情况 。
? 功能模型中所有的 数据流图 往往形
成一个 层次结构 。
? 在这个层次结构中,一个数据流图
中的过程可以由下一层的数据流图
做进一步的说明。
? 一般来讲,高层的过程相应于作用
在聚合对象上的操作,而 低层的过
程则代表作用于一个简单对象上的
操作 。
? 数据流图中允许加入控制流,但这样做
将与动态模型重复,不提倡夹带控制流。
基于三个模型的分析过程
? 功能模型着重于系统内部数据的传送
和处理 。
? 功能模型定义, 做什么,
? 动态模型定义, 何时做,
? 对象模型定义, 对谁做, 。
Coad与 Yourdon面向对象分析
? OOA有两个任务
? 形式地说明我们所面对的 应用问题,
最终成为软件系统基本构成的 对象,
还有系统所必须遵从的,由应用环
境所决定的规则和约束 。
? 明确地规定构成系统的 对象如何协
同合作, 完成指定的功能 。
OOA概念模型
? 通过 OOA建立的 系统模型是以概念
为中心的,因此称为概念模型。
? 这样的模型 由一组相关的类组成 。
? 软件规格说明就是基于这样的概念
模型形成的,以模型描述为基本部
分,再加上 接口要求、性能限制 等
其它方面的要求说明 。
构造 OOA概念模型的层次
? 构造和评审 OOA概念模型的顺序和
由五个层次组成。
? 这五个层次是分析过程中的层次。
? 每个层次的工作都为系统的规格说
明增加了一个组成部分。
? 这五个层次是,类与对象、属性、
服务、结构和主题 。
识别类和对象
? 面向对象分析的第一个层次主要是
识别类和对象 。
? 类和对象是 对与应用有关的概念的
抽象 。不仅是说明应用问题的重要
手段,同时也是构成软件系统的基
本元素。
? 这一层工作是整个分析模型的基础。
选择类和对象的原则,
? 目标系统必须记住类和对象的某些
事情
? 类和对象应当提供某些服务或处理
? 多属性
? 所有属性对于类中所有实例都应有
意义
? 对象类应表示问题论域的需求
基于语言的信息分析
? 在发现对象过程中,可以使用一种
十分有用的工具,即 LIA(基于语言
的信息分析 )。
? LIA的目的是 标识出问题论域的所
有概念及这些概念之间的关系 。
? 短语频率分析 (PFA)
? 矩阵分析 (MA)。
资源库
? 资源库包括 相关文件, 模型, 软件,
人员 以及 包含问题论域或系统知识
的其它资源 。 如果问题论域有参考
材料 (教材、惯例、操作过程等 ),
这些材料必须包含在资源库中。
? 资源库包括其它一些信息,访问记
录, 形式的或非形式的系统规格说
明, 已有的或 相关系统的用户手册,
日志 (如系统变更请求或问题报告 )。
? LIA技术通常只应用于 资源库的某个
子集 。这取决于分析员想把什么样的
视图用于问题论域或应用系统。
? 通常,根据与问题论域有关的资源建
立起来的结果与根据目标系统的规格
说明有关的资源建立起来的结果会有
所不同。
短语频率分析 PFA
? 短语频率分析搜索选定的问题陈述,
标识可以表示问题论域概念的术语。
? PFA清单的建立基本上是一个客观
的过程。但可能大多数标识出来的
概念是与目标系统无关的。
? PFA的优点就在于能 广泛地标识问
题论域的概念集合,并 对它们进行
评估, 判定哪些与目标软件无关 。
? PFA将名词和动词标识为候选实体
和属性 。但由于名词/动词的标识
是非常主观的,可根据什么是名词
或动词,以及根据分析员的理解,
才能确定哪些名词或动词是要找的。
? PFA是标识概念而不是标识语法单
元 。
? 所建立的 PFA清单并不受建立清单
的人的很大影响。
accepted subscription board of advisors correspondence address
accompanied payment brown wrapper,plain cost,shipping
accounting department bulk shipment country
actual expiration date bureau,subscription service country,foreign
additional subscription check payment credit card order
address,corporate commision,subscription credit card payment
address,correspondence service current author
address,home company subscription customer
address,subscription complimentary subscription database
advisors,board of complimentary subscription date,actual expiration
agency,subscription service query date,expiration
agreement,complimentary subscription date,expired
distributor-publisher review daleted,complimentary
annual subscription price complimentary subscription subscription
article deleted department,accounting
associated site constituent copies department,corporate
author continued subscription direct subscription
author,contributing contributing author discount,subscription


? 对于任一有用的应用论域资源,PFA
可能会产生一个长长的概念的清单 。
? 许多被标识出的概念因与目标软件无
关而被丢弃,但其它的则会成为 OOA
模型的成份,包括对象。
? 将 PFA清单转换为 OOA/ OOD工作
表格 。列出对各个概念的理解和选择,
这将有助于对象的选出。
Small Bytes 订阅系统 OOA/ OOD 工作表格
条 目 (0) (1) (2) (3) (4) (5) (6) (7) (8) 注 释
ACCEPTION
SUBSCRI PTION
× SUBSCRIPTION 的属性
ACCOMPANIED
PA YMENT
× 对 payment 的不同类型不加
以区分
ACCOUNTING
DEPAR TMENT
× 已超出 SBSS 的应用论域
ACTUAL EXPIRATION
DATE
× SUBSCRIPTION 的属性
ADDITIONAL
SU BSCRIPTION
× × SUBSCRIPTION 的可能属
性,或可能是派生类型 -基
类型结构
ARTICLE ×
ASSOCIATED SITE × SITE 的属性
AUTHOR ×
.....................
(0) 不适用,可能无关,超出指定系统的环境 (4) 可能描述对象的服务
(1) 可能的对象-类 (5) 与实现相关,可能是属于问题论域部分的条目
(2) 可能是派生类型-基类型结构的一部分 (6) 可能是属于人机交互部分的条目
包括泛化-特化结构和整体-部分结构 (7) 可能是属于任务管理部分的条目
(3) 可能描述对象-类的属性或实例关系 (8) 可能是属于数据管理部分的条目
标识结构
? 面向对象分析的下一步工作是 标识
结构 。典型的结构有两种:
? 一般化 -特殊化结构 ( Gen-Spec结
构 )
? 整体 -部分结构 ( Whole-Part结构 )
一般化 -特殊化结构
整体 -部分结构
? 以特殊化的视点来看,一个 Gen-Spec
结构 可以看作是,is a”或,is a kind
of”结构。例如,
a Truck Vehicle is a Vehicle
a Truck Vehicle is a kind of Vehicle
? 在 Gen-Spec结构 中,使用 继承 将较一
般化的属性和服务放在一般化的类和
对象中。
? 从整体的视点来看,一个 Whole-
Part结构 可看作一个,has a”或,is
a part of”结构。例如,
Vehicle has a Engine
Engine is a part of Vehicle
? 其中,Vehicle是整体对象,Engine
是局部对象。
标识 Gen-Spec结构的方法和策略
? 对于每一个类和对象,将它看作是一
个一般化的类,对它的所有特殊情况,
考虑以下问题:
? 它是否在问题论域中?
? 它是否在系统的职责内?
? 继承性是否存在?
? 它是否能够符合选择类和对象的标
准?
? 同样地,把每一个类和对象臵于特殊
化对象的地位,对于它所有的一般化
情形,考虑上述 4个问题。
? 检查以前在相同或类似问题论域中面
向对象分析的结果,看是否有可直接
复用的 Gen-Spec结构 。
? 如果一个一般化对象可能有多个特殊
化对象,应当先考虑 最简单的特殊化
对象 和 最复杂的特殊化对象,然后再
考虑中间其他的特殊化对象。
标识 Whole-Part结构的方法和策略
? 应当寻找什么
? 总体 -部分 ( Assembly-Parts)关联,
如 飞机 -发动机 之间的关系。
? 包容 -内含 ( Container-Content)
关联,如 飞机 -飞行员 之间的关系。
? 收集 -成员 ( Collection-Members)
关联,如 机构 -职员 之间的关系。
? 将每一个类 看作是一个 Whole类,
对它的所有可能 Parts情况,考虑以
下问题:
? 它是否在问题论域中?
? 它是否在系统的职责内?
? 它是否代表一个以上的状态值?
? 若不是,是否将它变为 Whole中
的一个属性?
? 它是否提供问题论域中有用的抽
象?
? 同样地,把每一个类臵于 Part 的地
位,对于它所有的 Whole情形,考虑
上述 5个问题。
? 检查以前在相同或类似问题论域中
面向对象分析的结果,看是否有可
直接复用的 Whole-Parts结构 。
标识属性
? 下一个层次称为属性层,对前面
已识别的类和对象做进一步的说
明。在这里,对象所保存的信息
称为它的属性 。
? 类的属性 所描述的是 状态信息,
每个实例的属性值 表达了 该实例
的状态值 。
标识属性的方法和策略
? 找出属性
? 将属性安放到适当的位臵
? 找出实例连接
? 检查特殊情况
? 描述属性
? 考虑取值范围、极限值、缺省值、
建立和存取权限、精确度、是否会
受到其他属性值等。
属性层
实例连接关系的标识
定义服务
? 对象收到消息后所能执行的操作称
为它可提供的服务。
? 对每个对象和结构的 增加, 修改,
删除, 选择 等服务 有时是隐含的,
在图中不标出,但在存储类和对象
有关信息的对象库中有定义。
? 其它服务则必须显式地在图中画出。
服务层
定义服务的方法和策略
? 找出每一个对象的所有状态,在各
种状态需要做的工作。利用状态迁
移图;
? 找出必要的操作。
? 建立消息连接。
? 描述服务:利用状态转换图、脚本
和事件追踪图,描述服务的功能。
消息连接的标识
? 两个对象之间可能存在着 由于通信
需要而形成的关系,这称为 消息连
接 。
? 消息连接表示从一个对象发送消息
到另一个对象,由那个对象完成某
些处理。 它们在图中用箭头表示,
方向从发消息的对象指向收消息的
对象。
找出消息连接的方法及策略
? 对于每一个对象,执行:
? 查询该对象需要哪些对象的服务,
从该对象画一箭头到哪个对象;
? 查询哪个对象需要该对象的服务,
从那个对象画一箭头到该对象;
? 循消息连接找到下一个对象,重
复以上步骤。
识别主题
? 主题可以看成是高层的模块或子系
统。
? 对于面向对象分析模型,主题表示
此模型的整体框架 。可以是一 个 层
次结构 。
? 通过对主题的识别,可以让人们能
够比较清晰地了解大而复杂的模型。
编辑管理的主题
识别主题
? 将 每一种结构 (包括 整体 -部分结构,
和 一般化 -特殊化结构 ) 中最上层的
类提升成为主题 ;
? 将各不属于任何结构的类提升主题 ;
? 检查在相同或类似的问题论域中以
前做面向对象分析的结果,看是否
有可直接复用的主题。
面向对象设计 ( OOD)
? 面向对象设计继续做面向对象分
析阶段的工作,建立软件的结构。
? 主要工作分为两个阶段:
? 高层设计
? 类设计
高层设计
? 高层设计阶段开发系统的结构,即构造应用软件的总体模型 。
? 高层设计阶段 标识在计算机环境中
进行问题解决工作所需要的概念,并增加了一批需要的类。
? 这些类包括那些可使应用软件与系
统的外部世界交互的类。
? 此阶段的输出是 适合应用软件要求
的类, 类间的关系, 应用的子系统
视图规格说明 。
高层设计模型
高层设计的特点
? 高层设计可以表征为 标识和定义模
块的过程 。
? 模块可以是一个单个的类,也可以
是由一些类组合成的子系统。
? 定义过程是职责驱动的 。
? 类接口的协议如同“合同”,需方
提出的请求必须列在协议表中,供
方则必须提供所有协议的服务。
高层设计应遵循的原则
? 应使得在子系统的各个高层部件之
间的通信量达到最小;
? 子系统应当把那些成组的类打包,
形成高度的内聚;
? 逻辑功能分组,提供一个一个单元,
识别并定位问题事件;
类设计
? 类与具有概念封装的子系统十分类
似 。
? 每个子系统都可以被当做一个类来
实现,这个类聚集它的部件,提供
了一组操作。
? 类和子系统的结构是正交的,一个
单个类的实例可能是不止一个子系
统的一部分 。
? 高层设计和类设计这两个阶段是 相
对封闭 的。
? 应用软件中的每一个事物都是一个
对象,包括应用软件自身在内 !
? 两个阶段是连接的。
? 应用软件的设计是大类的设计,这
种类设计考察应用软件所期望的每
一个行为,并利用这些行为形成应
用类的界面。
Coad 与 Yourdon 高层设计方法
? Coad 与 Yourdon 在设计阶段中继续
采用分析阶段中提到的五个层次。
? 在设计阶段中,这五个层次用于建
立系统的四个组成成份。
? 问题论域部分
? 人机交互部分
? 任务管理部分
? 数据管理部分
问题论域部分
? 问题论域部分 包括与应用问题直
接有关的所有类和对象 。
? 识别和定义这些类和对象的工作
在 OOA中已经开始,在 OOA阶段
得到的有关应用的概念模型描述
了我们要解决的问题。
? 在 OOD阶段,应当继续 OOA阶段
的工作,对在 OOA中得到的结果
进行改进和增补 。
问题论域部分的设计
? 在 OOA阶段得到的概念模型描述了
要解决的问题
? 在 OOD阶段,继续 OOA阶段的工作,
对在 OOA中得到的结果进行改进和
增补。
? 对 OOA模型中的某些类与对象、结
构、属性、操作进行组合与分解。
? 要考虑对时间与空间的折衷、内存
管理、开发人员的变更、以及类的
调整等。
1.复用设计
? 根据问题解决的需要,把从类库或
其它来源得到的既存类增加到问题
解决方案中去。
? 标明既存类中不需要的属性和操作,
? 增加从既存类到应用类之间的一般
化 -特殊化的关系。
? 把应用类中因继承既存类而成为多
余的属性和操作标出。
? 修改应用类的结构和连接。
2.把问题论域相关的类关联起来
? 在设计时,从类库中引进一个根类,
做为包容类,把所有与问题论域有
关的类关联到一起,建立类的层次 。
? 把同一问题论域的一些类集合起来,
存于类库中。
3,加入一般化类以建立类间协议
? 有时,某些特殊类要求一组类似的
服务。
? 此时,应加入一个一般化的类,定
义为所有这些特殊类共用的一组服
务名,这些服务都是虚函数。
? 在特殊类中定义其实现。
4,调整继承支持级别
? 在 OOA阶段建立的 对象模型中可能
包括有多继承关系,但实现时使用
的程序设计语言可能只有单继承,
甚至没有继承机制,这样就需对分
析的结果进行修改。
? 多继承模式有两种:
? 狭义的菱形
? 广义的菱形
针对单继承语言的调整
? 把特殊类的对象看做是一个一般类
对象所扮演的角色,通过实例连接
把多继承的层次结构转换为单继承
的层次结构。
? 把多继承的层次结构平铺,成为单
继承的层次结构。在这种情况下,
有些属性或操作在同层的特殊类中
会重复出现。
针对无继承语言的调整
? 当使用无继承的程序设计语言时,
必须把具有继承关系的类层次结
构平铺开来,成为一组类和对象。
? 一般可利用命名惯例,把这些类
或对象关联起来。
5,改进性能
? 提高执行效率和速度是系统设计的
主要指标之一。有时,必须改变问
题论域的结构以提高效率 。
? 如果类之间经常需要传送大量消息,
可合并相关的类以减少消息传递引
起的速度损失。
? 增加某些属性到原来的类中,或增
加低层的类,以保存暂时结果,避
免每次都要重复计算造成速度损失。
6,加入较低层的构件
? 在做面向对象分析时,分析员往往
专注于较高层的类和对象,避免考
虑太多较低层的实现细节 。
? 在做面向对象设计时,设计师在找
出高层的类和对象时,必须考虑到
底需要用到哪些较低层的类和对象 。
用户界面部分的设计
? 在 OOA 阶段给出了所需的属性和
操作,
? 在设计阶段必须根据需求把交互细
节加入到用户界面设计中,包括人
机交互所必需的实际显示和输入。
? 用户界面部分设计主要由以下几个
方面组成。
1,用户分类
? 按技能层次分类:
外行 / 初学者 / 熟练者 / 专家
? 按组织层次分类:
行政人员 / 管理人员 / 专业技术
人员 / 其它办事员
? 按职能分类:
顾客 / 职员
2,描述人及其任务的脚本
? 对以上定义的每一类用户,列出
对以下问题做出的考虑,什么人,
目的, 特点, 成功的关键因素,
熟练程度 以及 任务脚本 。
? 在 OOATOOLTM 中有一个例子:
? 什么人 ──分析员
? 目的 ──要求一个工具来辅助分
析工作 (摆脱繁重的画图和检查
图的工作 )。
? 特点 ──年龄,42岁;教育水平:
大学;限制:不要微型打印,小
于 9个点的打印太小。
? 成功的关键因素 ──工具应当使分
析工作顺利进行;工具不应与分
析工作冲突;工具应能捕获假设
和思想,能适时做出折衷;应能
及时给出模型各个部分的文档,
这与给出需求同等重要。
? 熟练程度 ──专家。
? 任务脚本 ──
? 主脚本,
? 识别“核心的”类和对象;
? 识别“核心”结构;
? 在发现了新的属性或操作
时随时都可以加进模型中去。
? 检验模型,
? 打印模型及其全部文档。
3,设计命令层
? 研究现行的人机交互活动的内容和
准则,这些准则可以是非形式的,
如“输入时眼睛不易疲劳”,也可
以是正式规定的;
? 建立一个初始的命令层,可以有多
种形式,如一系列 Menu Screens、
或一个 Menu Bar、或一系列 Icons.
? 细化命令层,考虑以下几个问题。
? 排列命令层次。 把使用最频繁的操
作放在前面 ; 按照用户工作步骤排
列 。
? 通过 逐步分解,找到整体-局部模
式,以帮助在 命令层中对操作分块 。
? 根据人们短期记忆的,7± 2”或
,每次记忆 3块/每块 3项,的特点,
把深度尽量限制在三层之内。
? 减少操作步骤,把点取、拖动和键
盘操作减到最少。
4,设计详细的交互
? 用户界面设计有若干原则,包括:
? 一致性,采用一致的术语、一
致的步骤和一致的活动。
? 操作步骤少,减少敲键和鼠标
点取的次数,减少完成某件事所
需的下拉菜单的距离。
? 不要“哑播放”,每当用户等
待系统完成一个活动时,要给出
一些反馈信息。
? Undo:在操作出现错误时,要
恢复或部分恢复原来的状态。
? 减少人脑的记忆负担,不应在一
个窗口使用在另一个窗口中记忆
或写下的信息;需要人按特定次
序记忆的东西应当组织得容易记
忆。
? 学习的时间和效果,提供联机的
帮助信息。
? 趣味性,尽量采取图形界面,符
合人类习惯,
5,继续做原型
? 用户界面原型是用户界面设计的
重要工作 。人需要对提交的人机
交互活动进行体验、实地操作,
并精炼成一致的模式。
? 使用快速原型工具或应用构造器,
对各种命令方式,如菜单、弹出、
填充以及快捷命令,做出原型让
用户使用, 通过用户反馈、修改、
演示的迭代, 使界面越来越有效 。
6,设计 HIC (人机交互 ) 类
? 窗口需要进一步细化,通常包括:
类窗口、条件窗口、检查窗口、
文档窗口、画图窗口、过滤器窗
口、模型控制窗口、运行策略窗
口、模板窗口等。
? 设计 HIC类,首先从组织窗口和部
件的用户界面界面的设计开始 。
? 每个类包括 窗口的菜单条, 下拉菜
单, 弹出菜单的定义 。还要定义用
于创建菜单、加亮选择项、引用相
应的响应的操作。
? 每个类负责窗口的实际显示 。所有
有关物理对话的处理都封装在类的
内部。必要时,还要增加在窗口中
画图形图符的类、在窗口中选择项
目的类、字体控制类、支持剪切和
粘贴的类等。与机器有关的操作实
现应隐蔽在这些类中。
7,根据图形用户界面进行设计
? 图形用户界面区分为 字型, 坐标系
统 和 事件 。
? 字型 是字体、字号、样式和颜色
的组合。
? 坐标系统 主要因素有原点 (基准
点 )、显示分辨率、显示维数等。
? 事件 则是图形用户界面程序的核
心,操作将对事件做出响应。
任务管理部分的设计
? 任务,是进程的别称,是执行一系
列活动的一段程序。
? 当系统中有许多并发行为时,需要
依照各个行为的协调和通信关系,
划分各种任务,以简化并发行为的
设计和编码。
? 任务管理主要包括任务的选择和调
整,它的工作有以下几种。
? 识别事件驱动任务, 一些负责与硬
件设备通信的任务是事件驱动的,
也就是说,这种任务可由事件来激
发。
?识别时钟驱动任务,以固定的时间
间隔激发这种事件,以执行某些处
理。某些人机界面、子系统、任务、
处理机或与其它系统需要周期性的
通信,因此时钟驱动任务应运而生。
? 识别优先任务和关键任务,根据
处理的优先级别来安排各个任务。
? 识别协调者,当有三个或更多的
任务时,应当增加一个追加任务,
起协调者的作用。它的行为可以
用状态转换矩阵来描述。
? 评审各个任务,对各任务进行
评审,确保它能满足选择任务的
工程标准 ─事件驱动?时钟驱动?
优先级 /关键任务?协调者?
定义各个任务
? 定义任务的工作主要包括,它是
什么任务, 如何协调工作 及 如何
通信 。
(1) 它是什么任务 ──为任务命名,
并简要说明这个任务。
(2) 如何协调工作 ──定义各个任务
如何协调工作。指出它是事件驱
动还是时钟驱动。
(3) 如何通信 ──定义各个任务之间
如何通信。任务从哪里取值,结果
送往何方。
(4) 一个模版 ──任务的定义如下:
? Name (任务名 )
? Description (描述 )
? Priority (优先级 )
? Servicesincluded (包含的操作 )、
? Communication Via (经由谁通
信 )。
数据管理部分的设计
? 数据管理部分提供了在数据管理系
统中存储和检索对象的基本结构,
包括对永久性数据的访问和管理。
? 它分离了数据管理机构所关心的事
项,包括文件、关系型 DBMS或面
向对象 DBMS等。
数据管理方法
? 数据管理方法主要有 3种,文件管
理, 关系数据库管理 和 面向对象
库数据管理 。
? 文件管理 ──提供基本的文件处
理能力。
? 关系数据库管理系统 ──关系数
据库管理系统使用若干表格来管
理数据。
? 面向对象数据库管理系统 ──通常,
面向对象的数据库管理系统以两种
方法实现:一是扩充的 RDBMS,
二是扩充的面向对象程序设计语言。
? 扩充的 RDBMS主要对 RDBMS扩充
了抽象数据类型和继承性,再加一
些一般用途的操作创建和操纵类与
对象。
? 扩充的 OOPL在面向对象程序设计
语言中嵌入了在数据库中长期管理
存储对象的语法和功能。
程序设计语言的影响
? 详细的面向对象设计与语言有关。
? 一般地,所有的语言都可以完成面
向对象实现,但某些语言能够提供
更丰富的语法,能够显式地描绘在
面向对象分析和面向对象设计过程
中所使用的表示法。
1,面向对象设计与过程型语言
? 过程型语言只直接支持过程抽象
? 可以增加数据抽象及封装 (如利用
结构化设计的信息隐蔽模块 )
? 无法明确地表示继承性。也无法明
确支持整体与部分、类与成员、对
象与属性等关系。
? 具有面向对象特性的过程型语言可
以成为一种实用的且可行的语言。
2,面向对象设计与基于对象的语言
? 基于对象的语言,也叫做面向软件
包的语言,如 Ada等
? 能够直接支持过程抽象、数据抽象、
封装和对象与属性关系
? 它无法表示继承性,也无法表示类
与成员、整体与部分的关系。
? 基于对象语言的面向对象设计代表
一种可行的开发方法。
3,面向对象设计与面向对象的
程序设计语言
? 面向对象的程序设计语言,包括
C++,Smalltalk,Objective-C、
Actor,Eiffel等,都直接支持过程
抽象、数据抽象、封装、继承、以
及对象与属性、类与成员关系。
? 它们不明确地支持整体与部分关系,
但可以方便地表示组装对象。
? 因此,从面向对象分析,到面向对
象设计,再到面向对象程序设计语
言是一种与表示法十分一致的策略。
4,面向对象设计与面向对象数
据库语言 (OO-DBL)
? 面向对象数据库管理系统 (OO-
DBMS)及其语言 (OO-DBL),是
面向对象程序设计语言 (OOPL)与
数据管理能力的组合。 OO-DBMS
有四种不同的体系结构:
? 大属性 ──扩充关系型 DBMS,使
容纳大属性,如一个文档。例如,
Informix公司的面向对象的产品。
? 松散耦合 ──一个 OOPL与大量的
DBMS组合在一起。
? 紧密耦合 ──一个 OOPL与某个专
用的 DBMS集成为一个系统。
? 扩充关系型 ──扩充关系型 DBMS,
可容纳“过程”之类的属性。
类的设计
? 应用分析过程包括了 对问题论域所
需的类的模型化
? 但在 最终实现应用时 不只有这些类,
还需要追加一些类
? 在类设计的过程中应当做这些工作。
? 单一概念的模型
? 使用多个类来表示一个“概念”。
? 常常把一个概念进行分解,用一组
类来表示这个概念。
? 也可以只用一个单个类来表示一
个概念。
? 在类的文档中应对 类的用途做出清
楚的标识和精确的陈述,类的共有
界面应当使用 操作的特征, 先决条
件 和 后臵条件 加以定义。
类设计的目标
? 可复用的“插接相容性”部件
? 部件可以在未来的应用中使用。
? 界面的标准化
? 类的“插接相容性”
? 可靠的部件
? 可靠的 (健壮的和正确定义的 )部
件。
? 每个部件必须经过充分的测试。
? 每个操作尽可能小和作用单一 。
? 可集成的部件
? 类的界面应当尽可能小
? 一个类所需要的数据和操作都定
义在类定义中
? 避免命名冲突
? 封装 特性保证了把一个概念的所
有细节都组合在一个界面下
? 信息隐蔽 保证了实现级的名字将
不会与其它类的名字互相干扰。
类设计的方针
? 信息隐蔽
? 保护抽象数据类型的存储表
示不被抽象数据类型实例的用
户直接存取 。
? 对其表示的唯一存取途径只
能是界面 。
直接引用类中的数据
通过界面引用类中的数据
? 消息限制
? 避开直接引用另一个类的数据
? 类 A的数据表示 中包括了 类 C的实
例, 类 B的数据表示 则直接使用了
类 C。 如果类 A的实例发送一个消
息给类 B的一个实例, 则类 A必须
知道类 B的实现是如何使用类 C的
实例的, 并把这种知识包括到它自
己的实现中去 。 当类 B需要改变自
己的实现, 改动类 C的数据表示时,
类 A的实现也必须随之改变 。
类间的相互影响
S e r v i c e
A t t r i b u t e
D i c ti o n ar y
S e r v i c e
A t t r i b u t e
A r r a y
S e r v i c e
A t t r i b u t e
I n v e n t or y
? 狭窄界面
? 不是所有的操作都是公共的。
? 对于一个 HashTable类,界面应包
括 插入 和 检索 表的操作,而不应包
括 使用一个表项的关键码计算散列
值 的操作。散列函数不应由类的实
例的用户来访问。它应是一个单独
的操作,以便容易调整或改变散列
函数,它应是隐蔽实现的部分。
? 强内聚
? 模块内部各个部分之间应有较强的
关系,它们不能分别标识。
? 弱耦合
? 一个单独模块应尽量不依赖于其它
模块。如果 ?在类 A的实例中建立了
类 B的实例,?类 A的操作需要类 B
的实例做为参数,?如果类 A是类 B
的一个派生类,?则称类 A“依赖于”
类 B。一个类应当尽可能少地依赖
于其它类。
? 显式信息传递
? 在类之间 全局变量的共享 隐含了
信息的传递,并且 是一种依赖形式 。
因此,两个类之间的交互应当仅涉
及显式信息传递 。
? 显式信息传递是通过参数表来完
成的 。借助于显式地列出将要通过
参数表传递给一个操作的值,可以
循特定的路径来跟踪错误。
? 显式信息传递要最小化
? 派生类当做派生类型
? 在继承结构中,每个派生类应该
当做基类的特殊化来开发,而 基类
所具有的公共界面成为派生类的共
有界面的一个子集 。
? C++允许设计者选择 类的基类 是
共有的 或 私有的 。
? 如果 基类是共有的,则 其共有界
面将成为新的派生类的共有界面部
分,这类似于类型与派生类型之间
的关系。
? 如果 基类是私有的, 它的行为将不
是派生类的公共行为部分而是实现
部分 。它的提出是为了提供实现新
类的服务。
? 在实现一个新类时 通过声明一个类
的实例,就可以使得该类的服务有
效。
? Dictionary类的实现可采用 Array
类的实例,这样可以把存储提供给
Dictionary项,而不给 Dictionary类
的界面增加不适当的操作。
? 抽象类
? 某些语言提供了一个类,用它 做
为继承结构的开始点,所有用户定
义的类都直接或间接以这个类为基
类。
? C++支持多重继承结构。 每一种
结构都包含了一组类, 它们是某种
概念的特殊化 。这个概念应抽象地
由结构的根类来表示。因此,每个
继承结构的根类应当是目标概念的
一个抽象模型 。
? 这个抽象模型 起始于一个根类,它
不产生实例。它定义了一个最小的
共有界面,许多派生类可以加到这
个界面上以给出概念的一个特定视
图。
? 考虑一组涉及,List”概念的类,根
类应提供一组操作做为界面而不考
虑是什么表。这个抽象类可以提供
某些操作的缺省实现,但在派生类
中将根据特殊化要求给出特定实现。
通过复用设计类
? 利用既存类来设计类,有 4种方式:
选择, 分解, 配臵 和 演变 。
? 选择
? 设计一个类最简单的服务是 从
既存的部件中简单地选择合乎需
要的软件部件 。
部件库
? 一个面向对象开发环境应提供一个
常用部件库。
? 大多数语言环境都带有一个初始部
件库,如整数、实数和字符,它是
提供其它所有功能的基础层。
? 任一基本部件库 (如“基本数据结
构”部件 )都应建立在这些原始层
上。
? 这个层还包括一组提供其它应用论
域方法的一般类,如窗口系统和图
形图元。
一个面向对象部件库的层次
? 特定组的部件 (一个小组为他们自
己组内所有成员使用而开发 )
? 特定项目的部件 (一个小组为某一
个项目而开发 )
? 特定问题论域的部件 (购自某一个
特定论域的软件销售商 )
? 一般部件 (购自专门提供部件的销
售商 )
? 特定语言原操作 (购自一个编译器
的销售商 )
? 分解
? 最初标识的“类”常常是几个概
念的组合 。在着手设计时,必须
把一个类分成几个类,希望新标
识的类容易实现,或它们已经存
在。
? 配臵
? 在设计类时,我们可能会要求由既
存类的实例提供类的某些特性。 通
过把相应类的实例声明为新类的属
性来配臵新类 。
? 一种 仿真服务器 可能 要求使用
一个 计时器 来跟踪服务时间。设
计者应当找到 计时器类,并在服
务器类的定义中声明它。
? 这个 服务器 还要求有一个 队列
类 的实例来作客户排队工作。
? 对每一个客户的服务时间由一
个已知的概率分布来确定,因此,
可能使用一个具有 泊松分布 或具
有 均匀分布 的随机变量的类的实
例。
? 演化
? 要求开发的 新类可能与一个既存类非
常类似,但不完全相同。此时,可以
利用继承机制。一般化 -特殊化处理
有三种可能的方式。
面向对象软件的实现与测试
? 在开发过程中,类的实现 是核心问
题。在只用面向对象风格所写的系
统中,所有的数据都被封装在类的
实例中 而 整个应用则被封装在一个
更高级的类中 。这种封装和类提供
的标准界面很容易把类所表达的特
性嵌入到应用中去。
类级关系
? 当我们实现类的时候就会遇到类
级的关系。
? 一个类的实现常常在某些方面依
赖于其它类的实例。类级关系可
以是应用级关系的实现,也可以
是类内属性的实现。
?消息
? 组装
? 继承
消息 (messaging)
? 在应用程序中,应用级关系大多是
以类的实例之间的消息连接方式实
现通信的。
? 在消息的参数表中指定消息的接受
者 (一个类的实例 )。还可以通过参
数表向接收者提供信息。
? 消息指定一个属于接收者的服务,
这个服务必须对应到该类共有界面
规定的行为。
? Dictionary类设计的例子
? 一个 Dictionary是包含一些可按关键
码的值排序和检索对象的部件。
? 对于要存储在 Dictionary内的一个实
例来说,
类必须提
供一个操
作来取得
关键码。
? 关系 refers to 表示了“一个类引用
另一个类”,后者的实例可当作参
数由前者在消息中使用。
? 由消息构成的流图形成了面向对象
系统结构的核心 。
? 例如,Dictionary类有一个操作 add,
该操作将把一个属于 Item类的对象
item当作参数,把这个对象加入到
Dictionary中。具体地,add操作首
先发送一个消息给做为参数的对象
item,再利用它的关键码,到该对
象所在的 Item类中引用 (refers to)相
应的实例,把它加入到词典中去。
? 在设计阶段,在这样两个类之间消
息关系的建立要求协调这些类的共
有界面的定义。
组装 (Composition)
? 组装关系是一个实现级关系,它对
应于应用级的聚合关系。
? 它也叫做 component(部件)或叫
做 is part of(是 … 的一部分)。
? 组装与消息两者都是类间的关系,
在这种关系中,一个类的实例将是
另一个类的实现的一部分。
? 考虑 Dictionary类的实现。
? 在 Dictionary中存储 item的一种数
据表示是使用散列表 (HashTable)。
? 进行 Dictionary类的低层设计时,
要指明在 Dictionary类和
HashTable类之间的一个 is part of
关系。
? 在实现时,应当在 Dictionary类的
定义中声明这个 Hash Table的实例。
继承 (Inheritance)
? 继承允许在既存类的基础上定义新
的类 。
? 一个新类 B继承了既存类 A,则 B包
括了 A定义的某些行为, 以及它自
定义的某些附加行为 。
? 有多少种面向对象程序设计语言,
就有多少种不同的继承实现方式 。
继承图
① 针对实现的继承
? 两个类之间“针对实现”的继承关
系的建立指的是 使用既存类的内部
表示来做为新类的内部表示的一部
分 。我们不推荐这种继承方式。
? 考虑使用继承来实现一个 Circle类,
为了定义一个圆,需要定义一个点
和一个值,做为圆的圆心和半径。
因此,Point类可支持 Circle类的一
部分实现。把 Point当做派生类。
? 如果 Circle类直接使用 Point的数据成
员 x和 y,将失去抽象。而且失去做为
一个点的圆心的标识。
? 针对实现的继承一般在原型开发中使
用。
② 针对特殊化的继承
? 这种继承的使用适合于大多数面向
对象程序设计语言所提供的关系,
是针对一般化 -特殊化关系的。
? 这种继承使用 is a关系。 类 B的一个
实例是 (is a)类 A的一个实例 。
? 在使用中,继承将使得既存类的界
面成为新类的界面 。这表明 新类具
有它的基类的所有行为 。
? 为了定义 Dictionary类,应当首先查
找既存的抽象,看 Dictionary类会是
哪个既存抽象的特殊情况。
? Dictionary应是一个有序表,但具有
它自己特有的操作, 如使用关键码进
行搜索等。既存的 Ordered List类可
以提供 Dictionary类的某些行为,但
不是全部。还要确认,在 Ordered
List中是否有的行为在 Dictionary 中
不需要。如果有,可能需要重新组
织层次或者开发某些追加的抽象。
is kind of (是一种 …) 继承
? 这种继承允许有选择地包含既存类
的属性,从而建立新的定义 。
? 一个 鸟 类可能有一个关于 飞行 的属
性。一个 鸵鸟 派生类在模型化时可
能就不选择这个属性,因为 鸵鸟 不
会飞 。 鸵鸟 是一种 ( is kind of )鸟,
但具有的属性与 鸟 不完全相同。
? is kind of 继承是不严格继承。
类的实现
? 一种方案是 先开发一个比较小的比
较简单的类, 做为开发比较大的比
较复杂的类的基础 。即从简单到复
杂的开发方案。
? 在这种方案中,类的开发是 分层 的。
一个类建立在一些既存的类的基础
上,而这些既存的类又是建立在其
它既存的类的基础上 。通过诸如
,is a”或,is part of”之类的关系,
利用既存代码就能着手建立新的类。
(1) 软件库 (Software Base)
? 建立软件库的目的是为了引用既存
的部件 。
? 存储在软件库中的类以多种途径发
生关联, 同时, 库可以追踪这些关
联 。
? 软件库工具利用这些关联可以有效
地进行开发 。
(2) 复用 (Reuse)
? 伴随着类的设计,应当从复用开始
着手类的实现。
? 类的设计可以使用各种抽象的类。
? 在类设计期间,我们必须开发这些
类中的“具体的”对象。
? 一旦一个数据对象被确认是应用所
需求的,则必须把它组织成类,以
便有效地提交所需要的模型。
产生所需功能的次序
? 寻找,原封不动 (As_is)”使用的既存
类,提供所需要的特性;
? 寻找可以用做开发新类的基础的既
存的类;
? 不用任何复用,开发一个新类。
-“原封不动”复用
? 所需要的类已经存在,我们 建立它
的一个实例,用以提供所需要的特
性。
? 这个实例可直接被应用利用,或者
它可以用来做另一个类的实现部分。
? 通过复用一个既存类,我们可得到
不加修改就能工作的已测试的代码。
-进化性复用
? 一个能够完全符合要求特性的类可
能并不存在。但 具有类似功能的类
存在,则 可以通过继承, 由既存的
类渐增地设计新类 。
? 如果新类将要成为一个既存类的派
生类,它应当继承这个既存类的所
有特性。然后新类可以对需要追加
的数据及必需的功能做局部定义。
? 还可以 将几个既存类的特性混合起
来开发出新的类 。每个既存类是某
些概念的模型。混合起来则产生了
一个为特定目标软件所用的具有多
重概念的类。
? 有时, 一个 既存的类可能会提供某
些在我们的新类中需要的特性以及
某些新类中不需要的特性 。 因此,
我们先 建立一个新的更抽象的类,
使之成为我们要设计的类的基类,
然后, 修改既存类以继承新的基类 。
? 既存类 A 的某些特性成为新类 B 的一
个部分,同时被类 A '和类 C 继承。
类 A 的某些特性保留在类 A '中,它不
被类 C 继承。
-“废弃性”开发
? 在新类的实现时,通过说明一些
既存类的实例,可以加快一个类
的实现。像表格、硬件接口,或
其它某些能力都可以用来作为一
个新类的局部。
(3) 断言 (Asserttions)
? 实现类的一个主动方法是把 来自类
的设计信息直接纳入代码 。特别要
求 把参数约束, 循环执行等编入到
代码中 。这可以通过某些表示断言
的语言机制来实现。
? 一个断言就是一个语句,它表达了
对一个过程、一个值,甚至一段代
码的 约束 。
? 在栈的描述中,可以使用断言来控
制进栈和退栈功能的操作:
procedure push (var S, Stack_Type;
New_Item, Item_Type);
assert,The stack S is not full
…………
assert,The top of stack S contains
New_Item
end;
procedure pop (var S, Stack_Type)
return Item_Type;
assert,The stack S is not empty
…………
assert,The stack S has one fewer
items that it did on entry
end;
? 先决条件
? 后臵条件
? 在 C与 C++中有一种头文件,叫做
,assert.h”,它支持断言的格式。
? 例如,实现者可以针对 pop操作,作
出断言如下:
assert (TOP> 0)
? 这样,宏就会检查 在试图从栈中退
出一项之前栈是否空 。如果条件测
试失败,则会打印出一条消息,报
告源文件名及在文件中发生失效的
行号。
(4) 调试 (Debugging)
? 数据封装 限定了许多用以修改数
据值的手段, 也 限定了对错误的
数据值进行调查以找出真正原因
的功能 。
? 某些面向对象的程序设计环境支持使用交互工具进行调试 。
? 工具包括 断点的设臵, 访问源代码, 检查对象 (包括修改数据值和
表达式求值 )及 编辑源代码 。
? 标准 UNIX调试工具 DBX已经做了
扩充, 可用于调试 C++程序 。
(5) 错误处理 (Error Handling)
? 我们期望 一个类能够自负错误处理
的责任 。类的实例负责定位和报告
错误。
? C在错误处理中使用 状态码 方法。
各种不同的状态码的值能够指明任
务的执行是成功还是失败,若是失
败又是哪种程度的失败。
? 例如,C中函数,fopen”返回的状态
码。如果打开失败,则返回零值;
如果打开成功,则返回文件的标志。
? 使用 状态码 方法的难点在于,各层
程序必须知道该层所调用函数的状
态码,并且检验这些状态码及采用
行动 。
? 问题在比它发生的那一层更高的一
层进行处理,这将产生比预想更高
程度的耦合。
? 问题尽可能在它发生的那一层进行
处理。例如,在 fopen打开文件失败
时,如果当前的文件名不存在,软
件可以要求用户键入另一个文件名。
(6) 内建错误处理 (Built_In Error
Handling)
? Ada程序员可以利用语言所提供的
例外处理机制 帮助做错误处理 。
? 一个, 例外, 所要做的事情是与众
不同的处理 。, 例外处理器, 是一
段代码, 一个特定的例外出现时调
用 。 它可以是终止软件的执行, 可
以是发信号给一个更高层的例外处
理器, 还可以是对问题进行定位处
理 。
package SIMPLE is
EQUAL, exception;
function max ( a, in INTEGER; b, in
INTEGER) return INTEGER;
--返回 a 与 b 中的最大值
--如果 a = b,则出现例外 EQUAL.
end SIMPLE;
package body SIMPLE is
function max (a, in INTEGER; b, in
INTEGER) return INTEGER is
begin
if a = b then raise EQUAL;
else if a < b then return b;
else return a;
end max;
end SIMPLE;
with SIMPLE;
procedure MAIN is
x, INTEGER;
begin
begin
x,= SIMPLE.max(7,7);
--将会出现例外
exception
when SIMPLE.EQUAL => x,= 7;
--处理例外
end;
--处理例外并给 x赋值?
end MAIN;
(7) 用户定义的错误处理
(User_Defined Error Handling)
? 有两种相对简单的错误处理技术,
它们提供了打印出错信息和终止软
件执行的能力 。 它们都不允许嵌套
的错误处理 。
? 第一种技术使用了一个 全局错误处
理器对象 。 每一个类都能对这个全
局对象进行存取 。
? 当在一个用户对象中检测出一个错
误的时候,就把一个 消息发送给这
个全局对象 。这个消息运载了一个
字符串,它就是要被打印的出错信
息,消息中还有一个整数,它指出
错误的严重程度。消息格式为:
ERROR_HANDLER.handle
("Message to be printed",1);
? ERROR_HANDLER将打印消息并
终止应用的执行。
? 第二种用户定义错误处理的技术要
求 每个类都定义或再定义一个命名
为 error的操作 。 这个操作不应是类
的共有界面部分, 它应是一个隐蔽
的实现部分, 可以被一些公共操作
调用以检测错误 。 这种 error操作可
以打印消息, 在适当时候请求一些
额外输入, 在必要时终止软件的执
行 。
(8) 多重实现
(Multiple Implementation)
? 同一个类可以多种方式实现 。为此,
软件库必须对库中的每一部分都能
保留充足的信息,使得定义能同时
关联到不止一个实现。
? 为了定义连接到几个实现所使用的
关系。程序员应能指出要求的实例
所在的类,并确定所期待的特定实
现。
应用的实现
? 应用的实现是在所有的类都被实现
之后的事情。
? 实际上,当把类开发出来时就已经
实现了应用。
? 每个类提供了完成应用所需要的某
种功能。
? 在 C++和 C中有一个 main( )函数。
可以使用这个过程来说明构成应用
的主要对象的那些类的实例。
? C++系统中主过程的两个主要职责
就是 建立实例 和 通过指针建立对象
之间的通信 。
? 以图形系统为例,首先 建立一个用
户界面的单一实例 。一旦它建立起
来,就发送一个消息, 启动绘图程
序的命令循环 。
? 然后,这个对象担负起在系统寿命
的其余时期协调通信关系和对象建
立的责任。
? 对于纯面向对象的语言,在系统中
的每个“事物”都是对象。
? 在这些语言中没有“主过程”。
? 用户建立起一个类的实例,然后,
通过实例接受控制和执行服务,产
生实例输出的结果或接收由用户发
送来的消息。
? 由那些原始消息而产生的消息序列
就成为目标软件的功能。
测试一个面向对象的应用
? 传统软件测试经历 单元测试, 组装测试, 确认测试 和 系统测试 等 4
个阶段。
? 单元测试 主要针对最小的程序单元 ?? 程序模块进行测试。
? 一旦这些程序模块分别测试完成
后,就将它们 组装 起来形成程序结构。
? 对整个 系统 进行一系列的测试,
查找和排除在需求方面的问题。
面向对象环境下的测试策略
? 单元测试 (类测试)
? 在面向对象环境下,最小的可
测试的单元是封装了的类或对象,
而不是程序模块。
? 面向对象软件的 类测试等价于
传统软件开发方法中的 单元测试 。
但它是由类中封装的操作和和类
的状态行为驱动的。
? 完全孤立地测试类的各个操作
是不行的。
? 考虑一个类的层次。 在基类中我
们定义了一个操作 X。
? 每一个派生类都使用操作 X,它是
在各个类所定义的私有属性和操作
的环境中使用的。 因使用操作 X的
环境变化太大, 所以必须在每一个
派生类的环境下都测试操作 X。
? 在面向对象开发环境下,把操作
完全孤立起来进行测试,其收效是
很小的。
? 组装测试
? 因为面向对象软件 没有一个层次
的控制结构, 所以 传统的自顶向下
和自底向上的组装策略 意义不大 。
? 每次将一个操作组装到类中 ( 像
传统的增殖式组装那样 ) 常常行不
通, 因为 在构成类的各个部件之间
存在各种 直接的和非直接的交互 。
? 对于面向对象系统的组装测试,
存在两种不同的测试策略 。
? 基于线索测试 (Thread-based Test)
? 它把 为响应某一系统输入或事件
所需的一组类组装在一起 。每一
条线索将分别测试和组装。
? 基于应用的测试 (Use-based Test)
? 它 着眼于系统结构,首先测试独
立类,这些类只使用很少的服务
器类。再测试那些使用了独立类
的相关类。一系列测试各层相关
类的活动继续下去,直到整个系
统构造完成。
? 确认测试
? 在进行 确认测试 和 系统测试 时,不
关心类之间连接的细节。着眼于用
户的要求和用户能够认可的系统输
出。
? 为了帮助确认测试的执行,测试者
需要 回到分析模型,根据那里提供
的事件序列(脚本)进行测试。
? 可以利用黑盒测试的方法来驱动确
认测试 。
? 测试方法学 检测软件中的故障 并 确
定软件是否执行了预定要开发的功
能 。
? 测试过程包括了 一组测试用例的开
发,每一个测试用例要求能检验应
用的一个特定的元素。还需要分析
用各个测试用例执行测试的结果来
收集有关软件的信息。
按不同层次进行测试
? 测试类中各个操作, 主要测试类
? 这种测试是某些 单元测试 与 组装
测试 的组合
? 假定 测试一个软件与测试一个类
一样 。 这个测试者常常就是一个
特定类的开发者 。
? 下面讨论测试, 主要集中于测试
类和它们的各个操作, 而不考虑
确认测试或其它系统测试 。
类的测试用例组
? 一个类的测试用例组由满足测试需
求的用例组成。
? 每个测试用例是一系列输入值,它
们将在要求的处理中执行,以满足
测试需求 。
? 每个测试用例应当包括 送给构造函
数的参数,以把对象在测试之前臵
于一个初始化的状态中。
类测试
? 类, 作为在语法上独立的部件,
应当允许用在许多不同的应用中 。
? 每个类都应是可靠的, 并且不需
了解任何实现的细节就能复用 。
? 因此, 类应尽可能孤立地进行测
试 。
测试类操作的测试用例组
? 首先定义 测试类的各个操作 的测
试用例组 。
? 然后再把测试用例组扩充, 针对
被测操作调用类中其它操作 的情
况, 进行组装测试 。
? 如果一个类中的 所有操作的先决
条件 和 后臵条件 都已定下来, 就
为各个独立操作的测试用例的开
发提供了指导 。
类测试的种类
? 基于定义的测试
? 把类当做一个黑盒对待,确认
类的实现是否遵照它的定义。例
如,若类是一个,Stack”,则测
试应当确保 LIFO 原则得以实施。
? 基于程序的测试
? 考虑类的实现,确定代码编写
得是否正确。例如,在 stack类中,
确认所有语句至少应被运行一次,同时正确地执行了操作。
基于定义的测试
? 基于定义的测试包括两个级别:
类定义和服务定义。
? 类定义
? 一个类的定义由各个服务的定义
和一些表示类的概念的语句组合
而成。
? 例,一个 stack类包括了服务
push和 pop的定义。还表达了
LIFO 的思想。
? C++中 类的定义是多层次的 。
? 对于大多数的类,检验类的定义
主要检验在类定义的 public域中所
包含的那些服务。
? 对于派生类,要检查包括 public和
protected这两个域在内的扩充界面。
? 如果完全地检查类中定义的服务,
则需要检查包括所有三个访问级别
public,protected以及 private的界
面。
? 服务定义
? 对于一个单独的服务,可通过该
服务的 先决条件 和 后臵条件,以
及它的名字加以定义。
? 根据先决条件选择测试用例,产
生输出,以便让测试者能够判断
后臵条件是否能够得到满足。
? 各个服务的定义的测试与对于各
个过程定义的测试基本相同。
基于程序的测试
? 基于程序的类的测试将 测试类的
各个服务,并 把类当做一个单元
进行测试 。
? 首先,测试计划考虑测试属于该
类的各个单个服务中的代码
? 然后考虑测试各个服务之间的相
互作用,类内通信 / 类间通信 。
? 测试可以覆盖 每个服务的整个输入
域 。 但这是不够的, 还 必须测试这
些服务的相互作用, 才能认为测试
是充分的 。
? 完全的单元 应当保证类的执行必须
覆盖它的一个有代表性的状态集合 。
? 构造函数和消息序列 ( 线索 ) 的参
数值的选择应当满足这个规则 。
处于隔离的服务
? 基于程序的测试考虑 测试每一个单
独的服务,可以使用那些与过程性
测试相同的方式对它们进行测试。
? 在测试一个服务与测试一个过程之
间最明显的不同就是 服务可能会改
变它所在的实例的状态 。
? 在测试一个服务时,该服务发送给
其它实例的消息都将被隔离,由桩
(stub)代替其它实例返回合适的值。
处于组装的服务
? 基于程序的测试需要考虑
? 在同一个类内部一个服务调用另
一个服务时的相互作用 (类内消息 )
? 从一个类到另一个类的消息 (类间
消息 )。
? 加入 检查相互作用的测试用例 到测
试用例组中,确定这种交互影响是
否处理得当。
? 类内测试需要 执行类的所有主要的
状态 。
组装测试
? 类组装
? 测试一个新类时,需要先测试在
定义中所涉及的类, 再考虑这些
类的组装 。
? 关系,is a”“is part of”和,refers
to”建立了测试几个类时的 次序之
间的关联 。一旦 基本类测试完成,
使用这些类的那些类可以接着测
试,然后按层次继续测试下去。
? 总体组装
? 把所有组成完整软件的各个部分
集合在一起。
? 在 C++的 主过程中, 仅建立几个
高层的和全局的类的实例,这些
实例之间必须经常互相通信。
? 这种测试所选择的测试用例应当
瞄准待开发软件的目标,并且应
当提供数据给测试者,以确定软
件开发是否与它的目标相吻合。
测试一个派生类
? 对基类和继承关系进行完全测试。
? 从基类的测试用例组复用已存在的
测试用例到派生类的测试用例组中 。
这种技术基于类的带有祖先的层次
关系,渐增地开发类的测试用例组,
因此叫做分层增殖式测试。
? 我们 首先安排一个针对单独的类的
测试计划, 然后考虑分层增殖式测
试计划和算法 。