介绍
重构[1]:对软件内部结构的一种调整,目的是在不改变"软件之可察行为"前提下,提高其可理解性,降低其修改成本。在这个定义中,"软件之可察行为"可以理解为相同的回归测试集,因此是确定、具体的。然而,虽然可以通过统计的方式计算”修改成本”,但是仍然缺乏可操作性。
在本文中,把“降低其修改成本”改成“降低复杂度”。从而利用复杂性量度给出重构的量化尺度,提高了重构定义的一致性。
软件量度[2][3]
主要的软件量度有如下几种:
1、 尺度性指标
- 代码行数,类成员个数,方法行数:越少越好
- 类个数:越多越好
2、 结构性指标:
- 继承深度:继承树的高度
- 方法加权和:每个方法的环形量度之和(cyclomatic)。简单地说就是条件和循环语句的个数加一。
- 对象间耦合:一个对象引用的其它类的个数。
- 类响应集合:一个消息响应可能调用方法的百分比。
- 方法内聚:一种算法是计算一个类中,百分之多少的方法调用了一个数据成员[4]。百分比越高,内聚越强。
- 封装性:不可见的成员/方法的百分比。
重构
软件量度可以为重构提供以下帮助:
- 软件量度可以识别出软件的坏味道。
- 软件量度可以衡量重构的效率
- 有很多重构操作也存在着有意义的逆向操作,这意味着需要一种权衡,这时量化量度更有帮助。
操作 |
逆向操作 |
量度变化 |
改名 |
|
名字的改变对软件量度来说没有影响。 当然名字会影响到可理解性, |
提炼方法 |
消除方法 |
方法行数发生变化,方法加权和可能变化 通常方法行数减少的时候,重用性会提高,从而降低整个软件的复杂度。 封装性发生变化 设置取值/改值方法 |
引入临时变量 |
消除临时变量 |
代码行数可能变化 改变临时变量的名字可以改善代码的可理解性 方法内聚性发生变化 将成员改成临时变量 |
移动方法/成员 |
提高封装性 有些成员/方法可能变成不可见。 |
|
提炼类 |
消除类 |
类的个数,方法内聚性,类成员个数发生变化 这些变化的利弊并不一致,需要加以权衡。 |
改成常数对象 |
改成变量对象 |
类响应集合发生变化 常数对象的行为比较简单,可提高代码的可理解性 |
改成单向关联对象 |
改成双向关联对象 |
对象间耦合发生变化 单向关联的耦合度更小一些 |
分解/合并条件式 |
方法加权和,方法行数发生变化 |
|
添加方法参数 |
减少方法参数 |
方法加权和,方法行数可能发生变化 如果引入参数对象,还会带来对象间耦合的变化 如果涉及到参数与成员的转换,方法内聚性也会发生变化 |
添加异常 |
减少异常 |
方法加权和,方法行数发生变化 这里使用异常并不能控制复杂度,相反还可能带来复杂度的增加 |
上移成员/方法 |
下移成员/方法 |
方法内聚性、代码行数发生变化 |
提炼接口 |
方法加权和,对象间耦合发生变化 值得注意的是封装性的变化,一个最小的公共方法集合可以提高封装性。 |
|
添加继承 |
减少继承 |
方法内聚性、代码行数,继承深度发生变化 如果可以保证超类/子类行为的一致性,那么添加继承后,方法内聚性会增加。 如果超类/子类行为并不一致,那么减少继承(比如改成委托),方法内聚性也会增加。 |
结语
软件量度是一种量化的,可以自动计算的指标。用于衡量软件重构的效果,可以得到客观的,比较一致的结果。
引用
[1] Martin Fowler,重构--改善既有代码的设计,中国电力出版社, 2003-8-1
[2] S. R. Chidamber and C. F. Kemerer, A metrics suite for object oriented design. IEEE Trans. Software Engineering, 20(6):476-493, 1994.
[3] F. B. Abreu and Walcelio Melo. Evaluating the impact of object-oriented design on software quality. In METRICS '96: Proceedings of the 3rd International Symposium on Software Metrics, page 90, Washington, DC, USA, 1996. IEEE Computer Society
[4] An Introduction to Object-Oriented Metrics, http://agile.csc.ncsu.edu/SEMaterials/OOMetrics.htm