张红华
摘要:既有软件重构工具大多数旨在解决局部设计或编码问题,并未涉猎设计层面。而以搜索为基础的重构方法虽然把改善代码度量指标作为重构目标,但是,却不是针对软件的层次化设计。对此,本文提出了一种全新的基于搜索的软件自动化重构方法,其通过利用以设计结构矩阵为载体的软件模块层次化度量方法,可以自动生成能够获取最优软件模块化设计的重构相关策略。
关键词:设计层次优化;软件重构;自动化
中图分类号:TP3 文献标识码:A 文章编号:1009-3044(2018)30-0276-02
1 软件自动化重构的意义
1.1 持续纠偏和改进软件设计
重构与设计之间是相互辅助的关系,两者之间是互补的。即使已经重构,也依旧需要进行预先设计,但是不需要是最优化设计,只需要制定可行的、合理的解决方案即可。而不进行重构,那么程序设计就会发生质变,导致无法控制。重构实际上就是进行代码整理,让带有发散倾向的代码及时回归到本位状态。软件的生命周期一般都需要大量的程序员进行维护工作,这就会导致后续被人为忽视。而为了保证代码容易理解,需要在实现软件功能的基础上,进行一系列相关工作,即清晰的排版布局,简要的注解,有效的命名。而命名是其中非常重要的一个环节,对此,可以采取暗喻命名的方法,也就是以对象实现的功能依据,使用形象化或者拟人手法进行命名。
1.2 有助于发现隐藏的代码缺陷
在进行代码重构的时候,需要对既有代码有深刻的了解。避免在写下程序之后,依旧对自己的程序逻辑缺乏理解。对此,一般可以进行代码重构,以此深化对既有设计的深刻了解,一旦发现其中存在的隐患,及时采取措施,构建更加优质代码。
1.3 有利于进一步提高编程效率
在发现解决问题是一件非常复杂的事情时,一般并非是问题自身所导致的,而是所选择的方法不正确,太过繁杂的设计会直接造成编码恶性重复。对此,有效改善设计,提高可读性,减缓缺陷是非常有必要的。较好的设计是成功的重要基础,虽然进行重构优化设计会导致速度有所下降,但是,其后续优势才是最关键的。
2 基于搜索的软件自动化重构
基于搜索的软件自动化重构是一种软件自动化重构研究中的普遍思想,其将软件重构抽象化,促使其成为属性、方法、类三者之间的组合优化,并通过搜索算法进行求解。Cinnéide通过利用基于搜索的软件自动化重构方法,实现了重构工具Code-Imp,其能够重构软件的设计层面,实现属性、方法、类之间的多种重构方式,即添加、取消或者代替继承关系。同时,此工具利用爬山、模拟退火、遗传等算法做了进一步的优化搜索。Cinnéide工作不仅有效实践了基于搜索的软件自动化重构,还对软件度量值间的彼此联系做了详细的对比分析。通过采取部分度量值进行研究,對比重构时度量值的变化,并对度量值间的关系与差异进行了考察。但是,Cinnéide并未深入探究软件模块层次化的度量。对此,本文应侧重于对具备较好模块层次化结构的代码进行适当调整。
3 基于设计层次优化的软件自动化重构的基本思想
DSM Re factoring主要是利用改变代码间的依赖关系,改善软件层次化结构,即输入某项目源代码,输出代码重构建议。通过源代码间的依赖关系,获得程序元素间的依赖关系。通过调整类和成员间的映射关系,提高源代码的模块化程度。利用遗传算法和DSM矩阵下的模块层次化度量法,计算类成员对类的最优映射关系。对既有类成员与类的映射关系,和遗传算法计算的最优类成员与类的映射关系进行对比分析,以此生成重构建议。把Java类间的依赖关系作为软件模块化和层次结构的重要根据,其主要是通过类属性与方法的相互依赖所产生,所以,可以适当改变类成员和类的映射关系,以此改变Java类间的依赖关系,进而改变项目层次结构。
4 基于设计层次优化的软件自动化重构算法过程
基于基本思想,利用遗传算法改变类成员与类间的映射关系,计算并对比软件结构所对应的模块层次化度量值,以此优化软件结构。重构遗传算法的搜索空间是类成员和类间映射的所有可能方式,软件模块层次化信息利用DSM进行描述,通过值L进行度量。
4.1 目标函数
4.1.1 度量
目标函数主要是以DSM模型与DRH理论为基础的,给定类成员与类的映射关系为个体,通过类成员的依赖关系,获得其在类间的依赖关系。利用DSM,行与列代表的设计变量都是Java类,变量间的依赖关系就是Java类间的依赖关系,主要是通过类的属性与方法间的调用关系进一步决定。每个Java类与其自身的依赖关系不需考虑,就DRH理论为基础,DSM的行与列可以重新排序,以此展示层次化结构,其中上下层之间是依赖关系。而软件层次结构的好坏是由度量值L决定的,DSM的L值是通过公式加以定义:
L=4×l2-4×n-m
其中,l代表行数,即Java类个数,n代表右上角1的数量,m代表左下角与层次化约束不相符的1的数量。在确定Java类个数的前提下,L值越大,表示软件层次化结构越好。
1)反向依赖
4×n主要针对DRJ的首个特征,DSM沿对角线形成的右上角为空。在DSM中,模块依赖是偏序的,所以,右上角出现依赖关系,代表着软件出现了反向依赖模块,不符合软件层次化要求,会造成L有所下降。因为DRH的偏序要求非常有必要,违反此要求的软件层次化结构很容易被腐化,因此,可以对此依赖关系应赋予更高的权重,其会对L值造成直接性影响。
2)跨层依赖
m针对的是另一层次化约束,其是针对DRH另一特征的,也就是在设计时,n层单纯依赖于1到n-1层。模块进行层次划分,依赖关系则只存在于相邻层次之间。在具备较好层次结构的软件设计划分成若干层次后,设计的n层只能单纯依赖于n-1层。
4.1.2 DSM矩阵L值计算
利用迭代方式计算代码结构DSM的度量值,首先聚类DSM的设计变量,将相互依赖的变量划分成同一模块。其次对模块进行层次划分,将相邻的独立模块划分到同一层次,并计算度量值,在此计算中,采取的方式是对所有可能的模块排列顺序进行一次性层次划分,并对度量值进行计算,以此保证度量值的精确性。作为DSM最终的度量值,最大值和设计变量的排列顺序都需要详细记录,而且度量值处于最大时,重构算法则直接结束。在聚类后,需要根据模块排列顺序对此进行层次划分,连续的两两独立模块都归属于相同层次。在计算度量值的时候,实际算法利用的DSM的每行所代表的都是划分后的层次。每个层次都利用大括号表示,而数字则代表层次中涵盖的Java类文件,数字表示一层次中依赖于另一次层次的Java类文件数量。
4.2 选择算子
在遗传算法中,选择算子主要是为了从同代个体中选择合适的个体产生下代,目标是将优胜个体遗传到下代,或者让优胜个体利用产生后代的方法遗传。选择算子就是为了从同代软件结构中,选择对应的最大度量值产生下代。在DSM Re factoring中,选择算子是最基础的比例选择算子,同代个体被选中的概率与所对应的度量值的比例,L值越大,被选中的概率越大。
4.3 交叉算子
交叉算子在遗传算法中的作用,就是提高算法的搜索水平与能力。通过重组选择算子的两个父代个体部分结构,产生下代新个体。交叉算子的作用主要就是交叉重组选择算子的父代软件结构,以生成新软件结构,在空间内搜索最优解。DSM Re factoring利用均匀交叉法,其实践概率为0.5,就此可知,在两个父代个体产生的下代个体软件结构内部,来自父代个体的软件结构各占50%。两个父代个体代表两种软件结构,分别以类成员列表加以表示,其中每个成员都详细记录了所在的Java類,在执行交叉前,克隆父代个体,并对其列表中的相关成员进行操作,其一,对两个克隆个体的成员所在类的一致性进行比较分析,如果一致,则结束操作;其二,在两个克隆个体中,成员所在类不一致,随机生产布尔值,值如果是真实的,则把克隆个体的成员所在Java类进行调换,相反则结束操作。据此,两个克隆个体转换成了新个体,经过变异算子操作之后,则会成为下代个体。
4.4 变异算子
变异算子主要是通过改动个体结构,提高遗传算法种群的多元性,从而防止出现遗传算法朝向局部最优解靠拢的现象。交叉算子的作用是改变需变异软件结构的部分结构,以此产生新的软件结构。DSM Re factoring中所使用的变异算子设计流程为:依据变异概率判断个体变异的必要性,从个体类成员列表中,随机选择属性或方法,将其依据既定概率移动到另一类中去。
5 结语
综上所述,目前我国在软件自动化重构方面的研究各式各样,但是既有重构工具大多注重局部代码重构,或者度量值重构,几乎不会对提升代码模块化质量的全方位重构进行考虑。因此,本文实现了基于设计层次优化的软件自动化重构,此方法是以遗传算法和DSM矩阵度量作为基础,对类成员与类的映射关系进行适当调整,并提出相关重构建议,其具有明显的优势,值得大力推广与应用。
参考文献:
[1] 刘嘉玥.基于启发式搜索的软件测试数据的自动生成[D].天津大学,2012.
[2] 王赞,樊向宇,邹雨果等.一种基于遗传算法的多缺陷定位方法[J].软件学报,2016,27(4):879-900.
[3] 陶彬贤.CODEREBUILDER:一种自动化Java并发程序重构工具的研究与实现[D].南京航空航天大学,2014.
[4] 高东静,林云,彭鑫等.面向设计层次优化的软件自动化重构[J].计算机应用与软件,2017,34(10):7-13.
【通联编辑:张薇】