第7章 问题域部分的设计
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第 4 页
4)如果近似,按如下的方法处理:
把要复用的类加到问题域,并标以{复用}。
去掉(或标出)复用类中的不需要的属性与操作,建立从复用类到 问题域原有的类之间的继承关系。
由于问题域的类继承了复用类的特征,所以前者中有些属性和操 作就不需要了,应该把它们去掉。
考虑修改问题域原有类与其他类间的关系,必要时把相应的关系 移到复用类上。 例如,问题域中有一个类“车辆”,其中的属性有:序号、颜色、 样式和出厂年月,还有一个操作为“序号认证”。现在找到了一个可 复用的类“车辆”,其中的属性有:序号、厂商和样式,也有一个操 作为“序号认证”。首先把可复用的类“车辆”标记为{复用},去掉 其中的不需要的属性“厂商”,把类“车辆{复用}”作为问题域中类 “车辆”的一般类,再把问题域中类“车辆”中的属性“序号”和 “样式”以及操作“序号认证”去掉,因为一般类中已经有了这些特 征,类“车辆”从中继承即可。 第 5 页
第 21 页
class 人员{ 采用聚合把多继承转换为单继承还有其他方式,如图7-7所示。 String name; int age; 在图7-7中,创建类“研究生”的对 graduate Gra; 象时,使用类“人员”、“研究生”和 institutor Ins; “身份”的信息,在这种情况下,类 void set(na, ag, gra, ins){ “研究生”那端的多重性取值为1。创 name =na; 建类“教职工”的对象也与此类似。创 age =ag; 建类“在职研究生”的对象时,要使用 Gra = gra; 类图中的四个类的信息,只是类“研究 Ins = ins; 生”和“教职工”那端的多重性均取值 } 为1。创建类“人员”的对象时,类"研 }
}
…… Gra=new graduate(); Ins=new institutor(); 图7-5多继承示例 图7-6 采用聚合的方式把多继承转换为单继承示例 第 20 页 人员 A;A. set(na,ag, Gra,Ins);
在图7-6中,用类“人员”创建对象的用意不变。创建一个 现实生活中的"研究生"对象时,使用类"人员"和类"身份"以及 自身的信息,类"教职工"也与此类似。创建"在职研究生"的对 象时,要使用类图中的四个类的信息。体会一下类"身份"那端 的多重性为1..2的原因。经过这样的转换后,新旧模型的语义不 能改变。
第 10 页
图7-1
合并后的类不再需要操作"取当前流速",取消它的原因是由于调用它过于频繁了。 第 11 页
(5)用聚合关系描述复杂类 如果一个类所描述的事物过于复杂,其操作也可能比较 复杂,因为其中可能要包括多项工作内容。对这种情况的处 理,可考虑用聚合关系描述复杂类。 例如,在一个动画播放系统中,可把每帧都定义为一个 对象。这样在显示时,既要显示背景,又要显示前景。由于 相对来说背景变化较少,一些连续的帧的背景经常是相同的; 而前景往往是变化的。把每个帧都作为一个对象来处理,显 然不容易针对背景和前景的不同特点设计出高效的算法。如 果把帧分解,形成如图7-2所示的结构,则能大大提高每帧的 显示速度。 图中的每个帧由一个背景和一个前景构成,但一个背景 可用于多个帧。
第 3 页
可复用的类可能与OOA模型中的类完全相同,也可能只 是相似。这要区分如下几种情况,分别进行处理。当前所需 要的类(问题域原有的类)的信息与可复用类的信息相比: 1)如果完全相同,就把可复用的类直接加到问题域,并用{复 用}标记所复用的类。 2)如果多于,就把可复用的类直接加到问题域,并用(复用} 标记所复用的类,所需要的类再继承它。 3)如果少于,就把可复用的类直接加到问题域,删除可复用 类中的多余信息,并用{复用} 标记所复用的类。
第 2 页
7. 1 为复用类而增加结构
如果在OOA阶段识别和定义的类是本次开发中新定义的, 且没有可复用的资源,则需要进一步设计和编程。如果已存在 一些可复用的类,而且这些类既有分析、设计时的定义,又有 源程序,那么复用这些类显然可以提高开发效率与质量。 在OOD阶段要尽可能使用可复用的成分。例如,如果存 在通用的类"图书",在零售书店领域,可设立较特殊的类"零 售图书"来继承它;而在图书馆领域,可设立类"馆藏图书"来继 承它。如果有可能,还要尽量寻找相同或相似的具有特定结构 的一组类进行复用,以减少新开发的成分。
第 17 页
7. 4 按编程语言调整继承
由于在OOA阶段强调如实地反映问题域,而在OOD阶段 才考虑实现问题,这就有可能出现这样的情况:在OOD模型中 出现了多继承,而所采用的编程语言不支持多继承,甚至不支 持继承。这就需要根据编程语言对问题域模型进行调整。 1.对多继承的调整
若编程语言支持单继承,但不支持多继承,则可按如下方法进行调整。 方法一:采用聚合把多继承换为单继承。 图7-4给出了一个示例。 第 18 页
第 6 页
不同程度的复用
可 复 用 类 定 义 的 信 息
比
当 前 所 需 的 类 的 信 息
=
直接复用
Fra Baidu bibliotek
<
> ≈
通过继承复用
删除可复用类的多余信息 删除多余信息,通过继承而复用
第 7 页
7. 2 提高性能
为了提高性能,需要对问题域模型做一些处理。影 响系统性能的因素有很多,下面给出一些典型的性能改 进措施。 (1)调整对象的分布 把需要频繁交换信息的对象,尽量放在一台处理机上。 (2)增加保存中间结果的属性或类 对经常要进行重复的某种运算,可通过设立属性和 专门的类来保存其结果值,以避免以后再重复计算。例 如,对于商品销售系统,可设立一个类“商品累计”, 用它的对象分门别类地记录已经销售出去的商品累计数 量,以免以后每次都从头重新计算。
第 12 页
图 7-2
第 13 页
(6)细化对象的分类 如果一个类的概念范畴过大,那么它所描述的对象的实 际情况可能就有若干差异。为了使这样的类的一个操作能够 定义一种对所有对象都适合的行为,就要兼顾多种不同的情 况,从而使得操作的算法较为复杂,影响执行效率。解决的 一个办法是把类划分得更细一些,在原先较为一般的类之下 定义一些针对不同具体情况的类。在每个特殊类中分别定义 适合各自对象的操作。 例如,有一个类"几何图形",为其编写一个通用的绘制 几何图形的操作肯定是比较复杂的,现在对几何图形进行细 分,分成多边形、椭圆、扇形等,再分别进行处理,如图7-3 所示。
第 14 页
图 7-3
图中分别按多边形、椭圆、扇形设计绘图操作,而不必考 虑通用性,所以设计出来的绘图算法相对来说是简单和高效 的。
第 15 页
7. 3 增加一般类以建立共同协议
在OOA中,将多个类都具有的特征,提升到一般类中,考虑的是问题域 中的事物的共同特征。在OOD中再定义一般类,主要是考虑到一些类具有共 同的实现策略,因而用一般类集中地给出多个类的实现都要使用的属性和操 作。如下为需要增加一般类的几种情况: 1) 增加一个类,将所有具有相同操作和属性的类组织在一起,提供通用 的协议。例如,很多类都应该具有创建、删除、复制等操作,可把它们放在 一般类,特殊类从中继承。 2) 增加一般类,提供局部通用的协议。例如,很多永久类都应该具有存 储和检索功能,可对这样的类设立一个一般类,提供这两种功能,永久存储 类从中继承。 上述两种情况都是通过建立继承关系,把若干类中定义了的相同操作提 升到一般类中,特殊类再从中继承。然而,在不同类中的操作可能是相似的 ,而不是相同的,有时需要对这种情况进行处理。 第 16 页
3) 对相似操作的处理。若几个类都具有一些语义相同但特征 标记相似的操作,则可对操作的特征标记做小的修改,以使得 它们相同,然后再把它们提升到一般类中。如下为两个策略: 若一个操作比其他的操作参数少,要加入所没有的参数, 但在操作的算法中忽略新加入的参数。这种方法存在一个缺点, 即对参数的维护和使用有些麻烦。 若在一个类中不需要父类中定义的操作,则该类的这种操 作的实现中就不含任何语句。 若经过上述处理后,在不同的类中的操作具有相同的语义, 但方法不同,则可以在这样的类间使用多态机制。
…… gra=new graduate(); 图7-7采用聚合的方式把多继承 ins=new institutor(); 转换为单继承示例 人员 A;A. set(na,ag, gra,ins);
究生"和类"教职工"那端的多重性均取 值为0。
第 22 页
方法二:采用压平的方式。还有一种简单的方法可用于把多 继承转换为单继承。在图7-8中,把类“在职研究生”直接 提升为类"人员"的子类。
图7-8 采用压平的方式把多继承转换为单继承
第 23 页
使用这种方法,使得类"教职工"和"研究生"中的一些特征要 在类"在职研究生"中重复出现,导致信息冗余。采用如图7-9所 示的方法,可解决该问题。
图7-9 采用压平和聚合的方式把多继承转换为单继承
图7-4 多继承中的一个继承换为聚合示例
因为聚合和继承是不同的概念,这种方法并不是通用的。例如, 类B拥有一个约束(如它仅能创建一个对象),类C通过继承也拥有 该约束,但换为聚合后,仅类B拥有该约束。在大多数情况下, 需要考虑形成多继承的原因,请看下面的例题。
第 19 页
class 人员{ 图7-5给出的模型中有一个多继承,现假设编程语言不支持多 String 继承,仅支持单继承。 name; int age; 由于在图7-5所示的模型中是按人员身份对一般类"人员"进行 identity idt[2]; 分类的,并形成了其下的两个特殊类"研究生"和"教职工",现在 void set(na,ag, Gra,Ins){ 用身份作为一个类,依据它对原模型进行调整。调整后的结构如 图7-6所示。 name =na; age =ag; identity idt[0]=Gra; identity idt[1]=Ins; }
第 8 页
(3)为提高或降低系统的并发度,可能要人为地增加或减少主 动对象
若把一个顺序系统变为几个并发任务,在执行时间上应 该缩短。但若并发的进程过多且量要频繁的协调,也需要额 外的时间。这也就是说,并发任务的设置和数量要适度,有 关该方言的更多内容请参见第9章。
(4)合并通信频繁的类 若对象之间的信息交流特别频繁,或者交流的信息量较 大,可能就需要把这些对象类进行合并,或者采用违反数据 抽象原则的方式,允许操作直接从其他对象获取数据。
上一章已经讲过,OOD的问题域部分以OOA的结果作为输入,按 实现条件对其进行补充与调整。在很多方面需要补充与调整:有的编程 语言不支持多继承和多态,在设计模型中就要去掉多继承,并考虑如何 不使用多态而仍能完成原有的功能;选用的网络与操作系统会影响对象 在不同站点上的分布、主动对象的设计、通信控制以及性能的改善措施 等;若能得到可复用的模型成分,则要对模型进行修改;根据需要还可 能要合并或分开一些类、属性或操作等等。 进行问题域部分设计,要继续运用OOA的方法,包括概念、表示法 及一部分策略。不但要根据实现条件进行OOD设计,而且由于需求变化 或新发现了错误,也要对OOA的结果进行修改。本章的重点是对OOA 结果进行补充与调整,要强调的是:这部分工作主要不是细化,但OOA 未完成的细节定义要在OOD完成。如下各节针对一些主要的情况讲述如 何进行问题域部分的设计。
第 9 页
例如,在某个实时控制系统中,要对一种液体的流 速进行自动控制。用一个流速探测器不断地探测液体的 流速,同时流速调节器要根据探测结果及时对流速进行 调节,使其稳定在一个流速范围内。最初的设计如图71a所示,用类“流速探测器”的对象中的操作“流速探 测”不地刷新属性“当前流速”,用类“流速调节器” 的对象中的操作“流速调节”反复地调用类“流速探测 器”的对象中的操作“取当前流速”,并把读取的当前 流速与属性“流速范围”比较,根据比较结果对设备进 行调节。如果两个对象间的频繁消息传送成为影响性能 的主要原因,则可以把两个类合并为一个类"流速调节 器",如图7-1b所示。
4)如果近似,按如下的方法处理:
把要复用的类加到问题域,并标以{复用}。
去掉(或标出)复用类中的不需要的属性与操作,建立从复用类到 问题域原有的类之间的继承关系。
由于问题域的类继承了复用类的特征,所以前者中有些属性和操 作就不需要了,应该把它们去掉。
考虑修改问题域原有类与其他类间的关系,必要时把相应的关系 移到复用类上。 例如,问题域中有一个类“车辆”,其中的属性有:序号、颜色、 样式和出厂年月,还有一个操作为“序号认证”。现在找到了一个可 复用的类“车辆”,其中的属性有:序号、厂商和样式,也有一个操 作为“序号认证”。首先把可复用的类“车辆”标记为{复用},去掉 其中的不需要的属性“厂商”,把类“车辆{复用}”作为问题域中类 “车辆”的一般类,再把问题域中类“车辆”中的属性“序号”和 “样式”以及操作“序号认证”去掉,因为一般类中已经有了这些特 征,类“车辆”从中继承即可。 第 5 页
第 21 页
class 人员{ 采用聚合把多继承转换为单继承还有其他方式,如图7-7所示。 String name; int age; 在图7-7中,创建类“研究生”的对 graduate Gra; 象时,使用类“人员”、“研究生”和 institutor Ins; “身份”的信息,在这种情况下,类 void set(na, ag, gra, ins){ “研究生”那端的多重性取值为1。创 name =na; 建类“教职工”的对象也与此类似。创 age =ag; 建类“在职研究生”的对象时,要使用 Gra = gra; 类图中的四个类的信息,只是类“研究 Ins = ins; 生”和“教职工”那端的多重性均取值 } 为1。创建类“人员”的对象时,类"研 }
}
…… Gra=new graduate(); Ins=new institutor(); 图7-5多继承示例 图7-6 采用聚合的方式把多继承转换为单继承示例 第 20 页 人员 A;A. set(na,ag, Gra,Ins);
在图7-6中,用类“人员”创建对象的用意不变。创建一个 现实生活中的"研究生"对象时,使用类"人员"和类"身份"以及 自身的信息,类"教职工"也与此类似。创建"在职研究生"的对 象时,要使用类图中的四个类的信息。体会一下类"身份"那端 的多重性为1..2的原因。经过这样的转换后,新旧模型的语义不 能改变。
第 10 页
图7-1
合并后的类不再需要操作"取当前流速",取消它的原因是由于调用它过于频繁了。 第 11 页
(5)用聚合关系描述复杂类 如果一个类所描述的事物过于复杂,其操作也可能比较 复杂,因为其中可能要包括多项工作内容。对这种情况的处 理,可考虑用聚合关系描述复杂类。 例如,在一个动画播放系统中,可把每帧都定义为一个 对象。这样在显示时,既要显示背景,又要显示前景。由于 相对来说背景变化较少,一些连续的帧的背景经常是相同的; 而前景往往是变化的。把每个帧都作为一个对象来处理,显 然不容易针对背景和前景的不同特点设计出高效的算法。如 果把帧分解,形成如图7-2所示的结构,则能大大提高每帧的 显示速度。 图中的每个帧由一个背景和一个前景构成,但一个背景 可用于多个帧。
第 3 页
可复用的类可能与OOA模型中的类完全相同,也可能只 是相似。这要区分如下几种情况,分别进行处理。当前所需 要的类(问题域原有的类)的信息与可复用类的信息相比: 1)如果完全相同,就把可复用的类直接加到问题域,并用{复 用}标记所复用的类。 2)如果多于,就把可复用的类直接加到问题域,并用(复用} 标记所复用的类,所需要的类再继承它。 3)如果少于,就把可复用的类直接加到问题域,删除可复用 类中的多余信息,并用{复用} 标记所复用的类。
第 2 页
7. 1 为复用类而增加结构
如果在OOA阶段识别和定义的类是本次开发中新定义的, 且没有可复用的资源,则需要进一步设计和编程。如果已存在 一些可复用的类,而且这些类既有分析、设计时的定义,又有 源程序,那么复用这些类显然可以提高开发效率与质量。 在OOD阶段要尽可能使用可复用的成分。例如,如果存 在通用的类"图书",在零售书店领域,可设立较特殊的类"零 售图书"来继承它;而在图书馆领域,可设立类"馆藏图书"来继 承它。如果有可能,还要尽量寻找相同或相似的具有特定结构 的一组类进行复用,以减少新开发的成分。
第 17 页
7. 4 按编程语言调整继承
由于在OOA阶段强调如实地反映问题域,而在OOD阶段 才考虑实现问题,这就有可能出现这样的情况:在OOD模型中 出现了多继承,而所采用的编程语言不支持多继承,甚至不支 持继承。这就需要根据编程语言对问题域模型进行调整。 1.对多继承的调整
若编程语言支持单继承,但不支持多继承,则可按如下方法进行调整。 方法一:采用聚合把多继承换为单继承。 图7-4给出了一个示例。 第 18 页
第 6 页
不同程度的复用
可 复 用 类 定 义 的 信 息
比
当 前 所 需 的 类 的 信 息
=
直接复用
Fra Baidu bibliotek
<
> ≈
通过继承复用
删除可复用类的多余信息 删除多余信息,通过继承而复用
第 7 页
7. 2 提高性能
为了提高性能,需要对问题域模型做一些处理。影 响系统性能的因素有很多,下面给出一些典型的性能改 进措施。 (1)调整对象的分布 把需要频繁交换信息的对象,尽量放在一台处理机上。 (2)增加保存中间结果的属性或类 对经常要进行重复的某种运算,可通过设立属性和 专门的类来保存其结果值,以避免以后再重复计算。例 如,对于商品销售系统,可设立一个类“商品累计”, 用它的对象分门别类地记录已经销售出去的商品累计数 量,以免以后每次都从头重新计算。
第 12 页
图 7-2
第 13 页
(6)细化对象的分类 如果一个类的概念范畴过大,那么它所描述的对象的实 际情况可能就有若干差异。为了使这样的类的一个操作能够 定义一种对所有对象都适合的行为,就要兼顾多种不同的情 况,从而使得操作的算法较为复杂,影响执行效率。解决的 一个办法是把类划分得更细一些,在原先较为一般的类之下 定义一些针对不同具体情况的类。在每个特殊类中分别定义 适合各自对象的操作。 例如,有一个类"几何图形",为其编写一个通用的绘制 几何图形的操作肯定是比较复杂的,现在对几何图形进行细 分,分成多边形、椭圆、扇形等,再分别进行处理,如图7-3 所示。
第 14 页
图 7-3
图中分别按多边形、椭圆、扇形设计绘图操作,而不必考 虑通用性,所以设计出来的绘图算法相对来说是简单和高效 的。
第 15 页
7. 3 增加一般类以建立共同协议
在OOA中,将多个类都具有的特征,提升到一般类中,考虑的是问题域 中的事物的共同特征。在OOD中再定义一般类,主要是考虑到一些类具有共 同的实现策略,因而用一般类集中地给出多个类的实现都要使用的属性和操 作。如下为需要增加一般类的几种情况: 1) 增加一个类,将所有具有相同操作和属性的类组织在一起,提供通用 的协议。例如,很多类都应该具有创建、删除、复制等操作,可把它们放在 一般类,特殊类从中继承。 2) 增加一般类,提供局部通用的协议。例如,很多永久类都应该具有存 储和检索功能,可对这样的类设立一个一般类,提供这两种功能,永久存储 类从中继承。 上述两种情况都是通过建立继承关系,把若干类中定义了的相同操作提 升到一般类中,特殊类再从中继承。然而,在不同类中的操作可能是相似的 ,而不是相同的,有时需要对这种情况进行处理。 第 16 页
3) 对相似操作的处理。若几个类都具有一些语义相同但特征 标记相似的操作,则可对操作的特征标记做小的修改,以使得 它们相同,然后再把它们提升到一般类中。如下为两个策略: 若一个操作比其他的操作参数少,要加入所没有的参数, 但在操作的算法中忽略新加入的参数。这种方法存在一个缺点, 即对参数的维护和使用有些麻烦。 若在一个类中不需要父类中定义的操作,则该类的这种操 作的实现中就不含任何语句。 若经过上述处理后,在不同的类中的操作具有相同的语义, 但方法不同,则可以在这样的类间使用多态机制。
…… gra=new graduate(); 图7-7采用聚合的方式把多继承 ins=new institutor(); 转换为单继承示例 人员 A;A. set(na,ag, gra,ins);
究生"和类"教职工"那端的多重性均取 值为0。
第 22 页
方法二:采用压平的方式。还有一种简单的方法可用于把多 继承转换为单继承。在图7-8中,把类“在职研究生”直接 提升为类"人员"的子类。
图7-8 采用压平的方式把多继承转换为单继承
第 23 页
使用这种方法,使得类"教职工"和"研究生"中的一些特征要 在类"在职研究生"中重复出现,导致信息冗余。采用如图7-9所 示的方法,可解决该问题。
图7-9 采用压平和聚合的方式把多继承转换为单继承
图7-4 多继承中的一个继承换为聚合示例
因为聚合和继承是不同的概念,这种方法并不是通用的。例如, 类B拥有一个约束(如它仅能创建一个对象),类C通过继承也拥有 该约束,但换为聚合后,仅类B拥有该约束。在大多数情况下, 需要考虑形成多继承的原因,请看下面的例题。
第 19 页
class 人员{ 图7-5给出的模型中有一个多继承,现假设编程语言不支持多 String 继承,仅支持单继承。 name; int age; 由于在图7-5所示的模型中是按人员身份对一般类"人员"进行 identity idt[2]; 分类的,并形成了其下的两个特殊类"研究生"和"教职工",现在 void set(na,ag, Gra,Ins){ 用身份作为一个类,依据它对原模型进行调整。调整后的结构如 图7-6所示。 name =na; age =ag; identity idt[0]=Gra; identity idt[1]=Ins; }
第 8 页
(3)为提高或降低系统的并发度,可能要人为地增加或减少主 动对象
若把一个顺序系统变为几个并发任务,在执行时间上应 该缩短。但若并发的进程过多且量要频繁的协调,也需要额 外的时间。这也就是说,并发任务的设置和数量要适度,有 关该方言的更多内容请参见第9章。
(4)合并通信频繁的类 若对象之间的信息交流特别频繁,或者交流的信息量较 大,可能就需要把这些对象类进行合并,或者采用违反数据 抽象原则的方式,允许操作直接从其他对象获取数据。
上一章已经讲过,OOD的问题域部分以OOA的结果作为输入,按 实现条件对其进行补充与调整。在很多方面需要补充与调整:有的编程 语言不支持多继承和多态,在设计模型中就要去掉多继承,并考虑如何 不使用多态而仍能完成原有的功能;选用的网络与操作系统会影响对象 在不同站点上的分布、主动对象的设计、通信控制以及性能的改善措施 等;若能得到可复用的模型成分,则要对模型进行修改;根据需要还可 能要合并或分开一些类、属性或操作等等。 进行问题域部分设计,要继续运用OOA的方法,包括概念、表示法 及一部分策略。不但要根据实现条件进行OOD设计,而且由于需求变化 或新发现了错误,也要对OOA的结果进行修改。本章的重点是对OOA 结果进行补充与调整,要强调的是:这部分工作主要不是细化,但OOA 未完成的细节定义要在OOD完成。如下各节针对一些主要的情况讲述如 何进行问题域部分的设计。
第 9 页
例如,在某个实时控制系统中,要对一种液体的流 速进行自动控制。用一个流速探测器不断地探测液体的 流速,同时流速调节器要根据探测结果及时对流速进行 调节,使其稳定在一个流速范围内。最初的设计如图71a所示,用类“流速探测器”的对象中的操作“流速探 测”不地刷新属性“当前流速”,用类“流速调节器” 的对象中的操作“流速调节”反复地调用类“流速探测 器”的对象中的操作“取当前流速”,并把读取的当前 流速与属性“流速范围”比较,根据比较结果对设备进 行调节。如果两个对象间的频繁消息传送成为影响性能 的主要原因,则可以把两个类合并为一个类"流速调节 器",如图7-1b所示。