面向对象软件耦合度量方法
马健1, 刘峰1, 樊建平2     
1. 北京交通大学 计算机与信息技术学院, 北京 100044;
2. 中国科学院 深圳先进技术研究院, 深圳 518055
摘要

针对面向对象设计的C&K度量组中耦合度量存在的问题,提出了一组分解的面向对象软件耦合度量方法.参考统一建模语言类图的定义分析了软件设计中类之间的关系,并使用一组形式化评估软件质量性质的定理进行评估,结果表明,新方法能够满足这些定理.最后使用JUnit和JEdit作为研究对象,利用DependencyFinder和Eclipse软件度量插件Metrics实现对软件耦合度量方法的自动计算,计算结果验证了该方法的有效性.

关键词: C&K度量组     软件质量     软件耦合度量     统一建模语言类图    
中图分类号:TP311 文献标志码:A 文章编号:1007-5321(2018)01-0109-06 DOI:10.13190/j.jbupt.2017-143
Object-Oriented Software Coupling Metrics
MA Jian1, LIU Feng1, FAN Jian-ping2     
1. School of Computer and Information Technology, Beijing Jiaotong University, Beijing 100044, China;
2. Shenzhen Institutes of Advanced Technology, Shenzhen 518055, China
Abstract

The article analyzes the shortage of C&K software metrics suit for an improvement, then proposes a decomposed coupling metrics for objected-oriented (DCMOO). The metrics refer to unified modeling language class diagram to analyze the relationships between classes in software design, and evaluate the quality of the software by using a set of formal evaluation theorems, It is shown that DCMOO can satisfy these theorems. Finally the article uses JUnit and JEdit as research object, and applies DependencyFinder and Eclipse Metrics to calculate the proposed software coupling metrics automatically meanwhile validate the proposed metrics.

Key words: C&K metrics suit     software quality     software coupling metrics     unified modeling language class diagram    

软件度量是一个范围很广的研究领域,其中软件的设计度量是面向结构度量和面向对象度量的一个结合点. Chidamber和Kemerer于1994年提出了6个面向对象设计的度量,通常被称为C&K度量组.软件设计度量研究中与软件设计水平紧密相关的耦合性度量研究是软件设计度量领域的一个研究热点. C&K度量组本身是不完备的[1],度量组中耦合度量方面存在着许多不足,例如:Hitz和Montazeri等[2]认为C&K度量组类间的耦合(CBO, coupling between object classes)度量没有对耦合的强度做区分,直接访问外部实例变量,这通常被认定为是最差的耦合类型,没有考虑继承耦合,即访问从超类继承的实例变量.这种耦合关系也被认为是最差的耦合类型之一,此外,没有考虑耦合的类型、耦合的扇入和扇出、接口的耦合.统一建模语言(UML, unified modeling language)类图主要是用来显示系统中的类、接口和它们之间的关系[3],在UML类图中,类与类之间的关系可以反映设计时它们之间的耦合性.因此,参考UML类图对耦合度量进行分析是合理的,可以很好地解决上述问题. Julianade等采用多元logistic回归分析方法探讨了C&K度量组CBO耦合度量的综合效应,没有讨论UML类图分析类之间的耦合[4]. Badri等[5]提出了一种度量标准,即在不同场景下使用不同的度量指标.例如不同场景下C&K度量组CBO耦合度量,没有涉及UML类图分析类之间的耦合. Mathru等[6]使用UML类图分析类之间的耦合关系,但没有对耦合关系进行分解.

笔者针对上述问题,参考UML类图定义的软件系统类之间的关系,经过研究与分析,得到一种分解的软件耦合度量方法(DCMOO, decomposed coupling metrics for objected-oriented),可以反映面相对象设计中的耦合关系.

1 面向对象的软件耦合度量 1.1 C&K度量组描述

C&K度量方法给出了6个基于类的设计度量:

1) 每个类的加权方法数(WMC, weighted methods per class):对于一个类C1,它定义了n个方法M1, M2, …, Mn, 而c1, c2, …, cn是每个方法相应的复杂度,类的加权方法数为$ \sum\limits_{i = 1}^n {{c_i}} $

2) 继承树的深度(DIT, depth of inheritance tree):DIT是类在继承树中的深度,如果存在多继承的话,DIT是该类在继承数中的最大深度.

3) 子类的数目(NOC, number of children):NOC是类的直接子类的数目.

4) 类间的耦合(CBO, coupling between object classes):CBO是某个类存在耦合关系类的数量.

定义1  与该类存在耦合关系其他类的数量.

$ C = \left| {\left\{ {d|u\left( {c, d} \right) \vee u\left( {d, c} \right)} \right\}} \right| $ (1)

定义2  与该类存在耦合关系其他类的数量,特别是指出它不包含继承耦合关系.

$ C' = C - \left| {\left\{ {d|a\left( {c, d} \right) \vee a\left( {d, c} \right)} \right\}} \right| $ (2)

其中:u(x, y)定义了类x的实现过程,使用了类y的方法、实例或属性,a(x, y)定义了类x是类y的父类.

5) 类的响应(RFC, response for a class):类的响应值为|RS|,其中RS是类对消息的响应集.响应集的值为{M}∪alli{Ri},{M}是类的方法集,{Ri}是被方法i调用的方法集.

6) 类内聚缺乏度(LCOM, lack of cohesion methods)

$ L = \left\{ \begin{array}{l} \left| P \right| - \left| Q \right|, \;\;\;\;\;{\rm{若}}\left| P \right| > \left| Q \right|\\ 0, \;\;\;{\rm{其他}} \end{array} \right. $

P={(Ii, Ij)|IiIj=Ø},Q={(Ii, Ij)|IiIj≠Ø}. {Ii}是方法Mi所用的实例变量集.

1.2 评估定理

文献[7]中描述了一组形式化评估软件质量性质的定理.

性质1  非粗糙性

$ \left( {\exists P} \right)\left( {\exists Q} \right)\left( {\mu \left( P \right) \ne \mu \left( Q \right)} \right) $

给定一个类P和度量μ,总能找到另一个类Q使得:μ(P)≠μ(Q).表明并不是每个类的度量值都相同,否则该度量就失去了它的价值.

性质2  非唯一性

$ \left( {\exists P} \right)\left( {\exists Q} \right)\left( {P \ne Q \to \mu \left( P \right) = \mu \left( Q \right)} \right) $

可以存在不同的类PQ,使得μ(P)=μ(Q).这意味着2个不同的类可以有相同的度量值,即这2个类具有相同的复杂性.

性质3  设计细节重要性

$ \left( {\exists P} \right)\left( {\exists Q} \right)\left( {P = Q \to \mu \left( P \right) \ne \mu \left( Q \right)} \right) $

设2个类PQ提供相同的功能, 不意味着μ(P)=μ(Q),类必须影响度量值.

性质3表明,虽然两类执行相同的功能,但设计的细节决定了类的度量.

性质4  单调性:

(∃P)(∃Q)(μ(P)≤μ(P+Q)∧μ(Q)≤μ(P+Q))对所有类PQ,必须有:μ(P)≤μ(P+Q)和μ(Q)≤μ(P+Q),其中P+Q表示PQ的组合.这意味着2个类度量值永远不会比其中任何一个小.

性质5  交互非等价性:

(∃P)(∃Q)(μ(P)=μ(Q))→(∃R)(μ(P+R)≠μ(Q+R))∃P,∃Q,∃R,使得μ(P)=μ(Q)不表明μ(P+R)=μ(Q+R),PR之间的相互作用不同于QR之间的相互作用导致P+RQ+R不同的复杂度值.

2 DCMOO方法描述

C&K度量组中与耦合相关的度量有:NOC、CBO和RFC.这里重点讨论CBO,与文中提出的DCMOO度量进行比较.

C&K度量组中的DIT和NOC度量可用于继承耦合,DCMOO度量也包含继承耦合,与DIT和NOC有功能上的重叠.

UML类图中认为类图之间的主要关系有:关联(Association)、依赖(Dependency)、泛化(Generalization)、实现(Realization).其中,耦合的强度为泛化=实现>关联>依赖.

参考UML中类图之间的关系,结合面向对象软件的特点,将类图中的泛化和实现关系合并,从这3个方面分析耦合度量,具体可分为:关联耦合度量(ACM, associated coupling metric)、依赖耦合度量(DCM, dependent coupling metric)和泛化耦合度量(GCM, generalized coupling metric).首先引入扇入和扇出耦合.

2.1 扇入扇出耦合度量

扇入扇出耦合:CBO没有区别耦合关系的扇入和扇出,首先对这种扇入和扇出耦合进行分析.

定义3  类间的扇入耦合(CBOin, coupling fan-in between object classes):该类(接口)耦合其他类(接口)的数量.

$ I = \left| {\left\{ {d|u\left( {d, c} \right)} \right\}} \right| $ (3)

定义4  类间的扇出耦合(CBOout, coupling fan-out between object classes):其他类(接口)耦合该类(接口)的数量.

$ O = \left| {\left\{ {d|u\left( {c, d} \right)} \right\}} \right| $ (4)

u(x, y)定义了类(接口)x的实现过程中,使用了类(接口)y的方法、实例或属性,它包含继承耦合关系.

存在类(接口)PQR,使得μ(P)≠μ(Q)和μ(P)=μ(R),因此,满足性质1和性质2.

一个类(接口)与另一个类(接口)有耦合关系,取决于耦合的方式并不是所提供的功能,因此性质3是满足的.

PQ是2个类(接口),并且μ(P)=nPμ(Q)=nQ,如果PQ合并,就会有μ(P+Q)=nP+nQ-,其中,PQ合并后减少的耦合关系数.显然,nP-≥0,nQ-≥0,耦合减少的不会比原来耦合的多,因此,对于所有的PQnp+nQ-npnp+nQ-nQ,性质4满足.

PQ是2个类(接口),μ(P)=μ(Q)=n,设R是另一个类(接口),μ(R)=r,有μ(P+Q)=n+r-μ(Q+R)=n+r-ββ是相互独立的,不会永远相等,所以μ(P+R)≠μ(Q+R).满足性质5.

在扇入扇出耦合度量的基础上,进一步细化为关联耦合度量(ACM)、依赖耦合度量(DCM)、泛化耦合度量(GCM).

2.2 关联耦合度量

定义5  关联耦合度量:ACM是软件系统中类(接口)c所关联的类(接口)的数量.

$ A = \left| {\left\{ {d|T\left( a \right) = d \wedge a \in F\left( c \right)} \right\}} \right| $ (5)

其中:F(c)表示类(接口)c的成员变量的集合,T(a)表示成员变量a的类型.

存在类(接口)PQR,使得μ(P)≠μ(Q)和μ(P)=μ(R),因此,满足性质1和性质2.

类(接口)之间有关联关系时,一个类(接口)的成员变量的类型为另一个类(接口),取决于关联的方式而不是所提供的功能,因此性质3是满足的.

PQ是两个类(接口)并且μ(P)=nPμ(Q)=nQ,如果类(接口)PQ合并,就会有μ(P+Q)=nP+nQ-,其中,PQ合并后减少的关联耦合数,显然,nP-≥0,nQ-≥0,因此,关联中减少的不比原来关联的数量多.对于所有的PQnp+nQ-npnp+nQ-nQ,性质4满足.

PQ是2个类(接口),μ(P)=μ(Q)=n,设R是另一个类(接口),μ(R)=r,有μ(P+Q)=n+r-μ(Q+R)=n+r-ββ是相互独立的,不会永远相等,所以μ(P+R)≠μ(Q+R).满足性质5.

2.3 依赖耦合度量

定义6  依赖耦合度量:DCM是软件系统中类(接口)c所依赖的类(接口)的数量.

$ D = \left| {\left\{ {d|a \in P\left( m \right) \wedge T\left( a \right) = d} \right\}} \right| $ (6)

其中:P(m)表示方法m的参数集、返回值和局部变量,T(a)表示成员变量a的类型.

存在类(接口)PQR,使得μ(P)≠μ(Q)和μ(P)=μ(R),因此,满足性质1和性质2.

类(接口)之间有依赖关系时,一个类(接口)的函数参数局部变量、参数或返回值的类型为另一个类(接口),取决于依赖的方式并不是所提供的功能,因此性质3是满足的.

PQ是2个类(接口),并且μ(P)=nPμ(Q)=nQ,如果类(接口)PQ合并,就会有μ(P+Q)=nP+nQ-.其中,PQ合并后减少的依赖耦合数,显然,nP-≥0,nQ-≥0,因此,依赖中减少的不比原来依赖的数量多,对于所有的PQnp+nQ-npnp+nQ-nQ,性质4满足.

PQ是2个类(接口),μ(P)=μ(Q)=n.设R是另一个类(接口),μ(R)=r,有μ(P+Q)=n+r-μ(Q+R)=n+r-ββ是相互独立的,不会永远相等,所以μ(P+R)≠μ(Q+R).满足性质5.

2.4 泛化耦合度量

定义7  泛化耦合度量:GCM是软件系统中类c所继承(实现)类(接口)的集合或接口c所继承接口的数量.

$ G = \left| {\left\{ {d|d \in R\left( c \right)} \right\}} \right| $ (7)

其中R(c)表示类(接口)c的父类(接口)集合或类c实现的接口.

存在类(接口)PQR,使得μ(P)≠μ(Q)和μ(P)=μ(R),因此,满足性质1和性质2.

类(接口)之间有泛化关系时,一个类(接口)的方法使用另一个类(接口)类型的成员变量和函数成员,取决于泛化的方式并不是所提供的功能,因此性质3是满足的.

PQ是2个类(接口),并且μ(P)=nPμ(Q)=nQ,如果PQ合并,就会有μ(P+Q)=nP+nQ-.其中,PQ合并后减少的泛化耦合数.显然,nP-≥0,nQ-≥0.因此,泛化中减少的不比原来泛化的数量多,对于所有的PQnp+nQ-npnp+nQ-nQ,性质4满足.

PQ是2个类(接口),μ(P)=μ(Q)=n,设R是另一个类(接口),μ(R)=r,有μ(P+Q)=n+r-μ(Q+R)=n+r-ββ是相互独立的,不会永远相等,所以μ(P+R)≠μ(Q+R).满足性质5.

3 实验结果与分析

JUnit是一个Java语言的单元测试框架,JEdit是一个用Java语言开发的文本编辑器.笔者使用JUnit4.3和JEdit5.4两个版本作为研究对象分析了度量值的计算结果.

实验使用了软件度量工具DependencyFinder和度量软件插件Eclipse Metrics实现对软件耦合度量值的计算.

表 1表 2所示为计算得出的JUnit4.3和JEdit5.4的CBO度量值.

表 1 JUnit4.3的CBO度量值

表 2 JEdit5.4的CBO度量值

大部分类的耦合度量值较小,只有少数类的耦合度量值较大.对象之间的过度耦合不利于模块的设计和重用.一个类越是相对独立,就越容易被重用于其他系统中.

表 3表 4所示为JUnit4.3和JEdit5.4的扇入/扇出耦合度量值.

表 3 JUnit4.3的扇入/扇出耦合度量值

表 4 JEdit5.4扇入/扇出耦合度量值

通过分析JUnit和JEdit的度量值方法可以得出以下结论:

1) 大部分类(接口)的扇入耦合和扇出耦合的度量值较小,只有少数类(接口)的扇入扇出耦合值较大;

2) 扇出耦合较小,但扇入耦合较大的类一般都为接口;

3) 为了提高模块化和封装性,应该尽量减少类(接口)之间的耦合.耦合关系的数量越大, 类(接口)也越容易受到其他部分改动的影响,因而维护也越困难.

表 5表 6所示为JUnit4.3和JUdit5.4的关联耦合度量值.

表 5 JUnit4.3的关联耦合度量值

表 6 JEdit5.4的关联耦合度量值

通过分析JUnit和JEdit的度量值可以得出以下结论:

1) 大部分类(接口)的关联度量值都较小;

2) 关联关系不利于模块化设计,减少关联关系有利于程序的修改、升级和测试;

3) 为了提高模块化和封装性,降低耦合强度,使得关联关系变得很少.

表 7表 8所示为JUnit4.3和JEdit5.4的依赖耦合度量值.

表 7 JUnit4.3的依赖耦合度量值

表 8 JEdit5.4的依赖耦合度量值

通过分析JUnit和JEdit的度量值方法可以得出以下结论:

1) 大部分类(接口)的依赖度量值都较大;

2) 依赖关系有利于模块化设计,有利于程序的扩展和重用,是一种较弱的耦合关系;

3) 为了提高封装性,降低耦合强度,使依赖关系增加,系统模块易于重用,系统容易扩展.

表 9表 10所示为JUnit4.3和JEdit5.4的泛化耦合度量值.

表 9 JUnit4.3的泛化耦合度量值

表 10 JEdit5.4的泛化耦合度量值

通过分析JUnit和JEdit的度量值方法可以得出以下结论:

1) 大部分类(接口)的泛化度量值都较小;

2) 泛化关系本身就是较强的耦合关系,系统中的继承为子类(接口)继承父类(接口),一个类实现另一个接口;

3) 为了提高多态性和封装性, 降低耦合强度,使得泛化关系变得较少.

4 结束语

分析了C&K度量组中类间耦合CBO的不足,参考UML中类图之间的关系,对CBO度量指标进行了改进,并使用一组形式化评估软件质量性质的定理进行评估;以JUnit和JEdit为研究对象,对提出度量框架的关联、依赖、泛化关系进行度量研究.结果分析表明,DCMOO可以较准确地反映面向对象设计中的耦合关系.设计良好的面向对象系统,其面向对象设计度量的值也较为合理;反之,设计较差的面向对象系统,其面向对象设计度量的值也并不甚合理,从而验证了方法的有效性.

新方法的提出揭示了面向对象开发设计的一定规律,对软件产品的解耦合和维护升级也有一定的指导意义.

参考文献
[1] Chidamber S R, Kemerer C F. A metrics suite for object oriented design[J]. IEEE Transactions on Software Engineering, 1994, 20(6): 476–493. doi: 10.1109/32.295895
[2] Hitz M, Montazeri B. Measuring coupling and cohesion in object-oriented system[C]//Proceedings of International Symposium on Applied Corporate Computing(ISAAC 95). Mexico: Springer, 1995: 78-84.
[3] 冯跃忠, 李晓峰. 基于规则库的电信业务UML活动图验证机制[J]. 北京邮电大学学报, 2008, 31(2): 76–79.
Feng Yuezhong, Li Xiaofeng. A rule database based UML activity model checking mechanism in telecommunication service[J]. Journal of Beijing University of Posts and Telecommunications, 2008, 31(2): 76–79.
[4] Juliana de A G Saraiva, MicaelS de França, SérgioC B Soares, et al. Classifying metrics for assessing object-oriented software maintainability:a family of metrics' catalogs[J]. Journal of Systems & Software, 2015, 103(C): 85–101.
[5] Badri M, Toure F. Empirical analysis of object-oriented design metrics for predicting unit testing effort of classes[J]. Journal of Software Engineering & Applications, 2014, 5(7): 513–526.
[6] Mathru B, Kaushik M. Empirical analysis of metrics using UML class diagram[J]. International Journal of Advanced Computer and Applications, 2016, 7(5): 32–37.
[7] Srinivasan K P, Devi T. Software metrics validation methodologies in software engineering[J]. International Journal of Software Engineering & Applications(IJSEA), 2014, 5(6): 87–102.