经过测试的OO软件,是否满足要求呢?如何用这些结果来判断OO软件的质量呢?实际上OO软件的度量就是让软件开发——
度量(measurement)与量度(metrics)是任何工程学科的关键部分,它们有何区别呢?度量是对开发过程进行检测,以提高开发过程的质量和劳动生产率;量度则是度量的结果,作为评价质量和劳动生产率的基础。与其他方法相比较,OO量度的使用和发展要晚得多。与传统软件一样,OO量度的主要目的是:更好地理解产品的质量,评价过程的效率,改进项目层完成工作的质量。
一、OO度量的特性
任何产品的技术量度都取决于产品的特性。OO软件与使用传统方法开发的软件的度量方法截然不同,OO软件目前常用的五个特殊量度的特性包括以下几个:
1.局域性
局域性(Localization)是指信息被集中在一个程序内的方式。
(1)传统方法:数据与过程分离,功能分解和功能信息局域化。其典型的实现形式为过程模块,工作时用数据驱动功能。
此时的量度放在功能内部结构和复杂性上(如模块规模、聚合度、环路复杂性等)或放在该功能与其他功能(模块)的耦合方式上。
(2)OO方法:局域性基于对象,因为类是OO系统的基本单元,对象封装数据和过程,因此应把类(对象)作为一个完整实体来量度。
另外,操作(功能)和类之间的关联是一对一的。因此,在考虑类合作中的量度时,必须能适应一对多和多对一的关联。
2.封装性
封装(Encapsulation)是指一个项集合的包装。
(1)传统方法:记录、数组,只有数据没有过程,为低层次的封装;过程、函数、子例程和段,则只有过程没有数据,为中层次的封装。其量度的重点分别在代码行的数据和环路的复杂性。
(2)OO方法:OO系统封装拥有类的职责(操作),包括类的属性、操作和特定的类属性值定义的类(对象)的状态。其量度和重点不是单一的模块,而是包含数据(属性)和过程(操作)的包。
3.信息隐藏
信息隐藏(Information hiding)是指隐藏(删除)了程序构件操作的细节,只将访问该构件所必要的信息提供给访问该构件的其他构件。
在这一点上,OO方法和传统方法基本一致。因此,OO系统应支持信息隐藏,除提供隐藏等级说明的量度外,还应提供OO设计质量指标。
4.继承性
继承性(Inheritance)是指一个对象的属性和操作能够传递给其他对象的机制。继承性的发生贯穿于一个类的所有层次。
一般来说,传统软件不支持这种特性。而对OO系统来说,继承性是一个关键性的特性。因此,很多OO系统的量度都以此为重点,如子的数量(类的直接实例数量),父的数量(直接上一代数量),以及类的嵌套层次(在一个继承层次中,类的深度)。
5.抽象
抽象(Abstraction)使设计者只关心一个程序构件的主要细节(数据和过程两者),而不考虑底层的细节。
抽象也是一种相对概念,抽象在OO和传统开发方法中都被采用,如处于抽象的较高层次时,我们可忽略更多的细节,只提供一个关于概念或项的一般看法;当处于抽象的较低层次时,可以引入更多的细节,即提供一个关于概念或项的更详细的看法。
在OO中,由于类是一个抽象,它可以从许多不同的细节层次和用许多不同的方式(如作为一个操作的列表、一个状态的序列、一组合作)来观察。
OO量度可用一个类度量的项来表示抽象,如每个应用类的实例化的数量、每个应用类被参数化的数量,以及类被参数化与未被参数化的比例等。
二、面向类的量度
类是OO系统的基本单元。一个单一类、类的层次和类的合作的度量和量度,对一个必须评价设计质量的软件工程是十分重要的。
1. CK量度组
CK量度组由Chidamber和Kemerer提出,他们建议使用6种基于类设计的量度,通称为CK量度组。
(1) 每个类的加权方法WMC (weighed Methods per Class)
WMC=∑Ci (i=1~n)
其中,Ci为一个类的各个方法(或操作或服务)的复杂性,相当于传统方法中的环路复杂性,Ci可相加。方法的数量和它们的复杂性是用来实现和测试一个类工作量总量的指示器。方法的数量越大,继承树(所有子类都继承父类的方法)就越复杂。对一个给定的类,随着方法的数量增大,其应用很可能变得越来越专门化,由此将限制其可能的重用。所以,WMC的值应当合理。
(2) 继承树的深度DIT (Depth of the Inheritance Tree)
这种量度被定义为从结点到树根的最大长度。
DIT的值越大,复杂性就越高。因为随着DIT的增大,层次的类可能会继承许多方法。当试图预测一个类行为时,困难不仅会增大,而且会增加设计的复杂性。当然DIT较大时,则表示有许多方法被重用,这是其好的一方面。
(3) 子的数量NOC (Number of children)
子类在类的层次内,子类可以最直接地从属于一类。随着子类数量的增大,重用也增加了。但父类抽象的表示可能减少,即一些子类可能不是父类真正的成员,同时,测试数量(用来检查每个子类在操作前后的要求)也将增加。
(4) 对象类间的耦合CBO
CBO(Coupling Between Object Classes)是指一个类合作(即相关)的数量。当CBO增大时,不仅降低了可重用性,而且使其修改和修改后的测试变得复杂。所以,每个类的CBO值应当保持合理。这与在传统软件中减少耦合的一般原则是一致的。
(5) 对一个类的响应RFC (Response for a Class)
一个类的响应设置是一组方法,它可能被执行,用来响应接收到的类对象的消息,RFC被定义为响应设置方法的数量。
RFC增加,测试序列增加,测试工作量也将增加。由此可以得出,当RFC增大时,类的设计复杂性也将增大。
(6) 方法中聚合的不足LCOM (Lack of Cohesion in Methods)
一个类内的每种方法访问一个或多个属性(也称实例变量)。LCOM是访问一个或多个相同属性方法的数量。
如果LCOM很大,则说明方法可以通过属性与其他方法耦合,这就增加了类设计的复杂性。通常,对LCOM值很大的类,可以把它分为两个或多个单独的类,这样每个类能的设计更方便。
这里讲的耦合和聚合与传统软件中所讲的是一样的。我们希望高聚合和低耦合,即保持低的LCOM。但在某些情况下,LCOM值很大也是合理的。
2. LK量度组
LK量度组是由Lorenz和Kidd提出的,他们把基于类的量度分为四种类型:规模、继承、内部(特性)和外部(特性)。
对OO类,基于规模的量度,主要集中在单一类的属性和操作的数量,以及作为整个OO系统的平均值;基于继承的量度,关注的是贯穿于类层次的操作被重用的方式;类的内部特性的量度是考察聚合和代码问题;而外部特性的量度则是检查耦合和重用问题。
三、面向操作的量度
根据Lorenz和Kidd的建议,有三种基本量度:
(1) 平均操作规模OSavg (Average Operation Size)
虽然代码行数可以成为操作规模的指示器,但代码行数的度量与传统软件一样有许多问题。因此,在OO软件中,由操作所传送的消息数量提供了一个对操作规模度量可选的方法。操作规模增大,表示操作所传送的消息数量增加,数量越大,说明越复杂。
(2) 操作复杂性OC (Operation Complexity)
一个操作的复杂性可以用传统软件所使用的任何复杂性量度进行计算。因为操作限于特定的职责,所以设计人员应使OC尽可能的小。
(3) 每个操作参数的平均数NPavg (Average Number per Operation)
操作参数的数量越大,对象间的合作就越复杂。所以,NPavg 一般应尽可能的小。
四、OO系统的量度
根据Binder建议,按对封装性和继承性的影响提出了几种类型的量度。
1. 封装性
(1) 方法(操作与服务)中聚合的不足LCOM LCOM的值越高,表示更多的状态必须进行测试,才能保证方法不产生副作用。
(2) 公共与私有的百分比PAP (Percent Public and Protected)
公共属性从其他类继承,所以这些类是可见的。私有属性是专属的,为一特定子类所拥有。这种量度说明类的公共属性的百分比,PAP的值高就可能增加类间的副作用。
(3) 数据成员的公共访问PAD (Public Access to Data Member)
这种量度说明可访问其他类属性的类的数量,即一种封装的破坏。PAD的值高可能导致类间的副作用。所以,测试的设计必须保证每一种这样的副作用能够被发现。
2. 继承性
(1) 根类的数量NOR (Number of Root Classes) 这种量度是在设计模型中,描述性质各不相同的类层次数量的计算方法。对每一个根类及其子类的层次必须开发相应的测试序列。随着NOR的增大,测试工作量也相应增加。
(2) 扇入FIN (Fan In) 当扇入用于OO情况时,扇入是一种多重继承的指标。FIN大于1
,说明一个类不只从属一个根类,而是继承更多的根类的属性和操作。
(3) 子的数量NOC (Number of Children)和继承树的深度DIT (Depth
of the Inheritance Tree) 正如在OO测试中讨论的,超类的方法(操作、服务)将不得不为每个子类进行重新测试。
五、OO项目的量度
项目管理人员的任务就是计划、协调、跟踪和控制一个软件项目的进行。其中主要问题就是对软件的实现规模进行估算。因为规模与工作量和开发时间成正比。
(1) 脚本的数量NSS (Number of Scenario Scripts) 脚本的数量或使用用例与满足需求所要求的类的数量、每个类的状态的数量,以及方法(操作)、属性和合作的数量成正比。所以,NSS是程序规模的重要指标。
(2) 关键类的数量NKC (Number of Key Classes) 关键类一般都集中在问题的事务域上,而且它通过重用来实现的可能性很小。因此,NKC的值高表明实际的开发工作还处于初期阶段。Lorenz和Kidd认为,在一般的OO系统中,关键类应在20%~40%,而其他类支持底层结构(GUI、通信、数据库等)。
(3) 子系统的数量NSUB (Number of Subsystems) 子系统的数量能对资源分配、进度安排(特别强调采用平行开发)及整个集成的工作量提供更好的了解。
NSS、NKC和NSUB的量度还可以用来收集与过去OO项目及其整个项目和单个过程活动(如OOA、OOD、OOP和OOT)相关的工作的花费。这些数据也可以与前面讨论过的设计量度一起用来计算生产率量度,如每个开发人员开发类的平均值等。总之,这些量度可以用于估算当前项目的工作量、开发时间、使用人员和其他信息。
(计算机世界报 第13期 B9、B10)
|