梁朋举 刘建宾 郑丽伟
(北京信息科技大学计算机学院 北京 100101)
程序蓝图模型重构操作实例研究
梁朋举刘建宾郑丽伟
(北京信息科技大学计算机学院北京 100101)
重构可以改善软件系统的内部结构,提高软件可理解性、可维护性,而又不改变软件的外部行为。传统的源码层次的重构虽有很多重构工具的支持,但是对于复杂软件的重构难度大,容易出错。针对这种情况,提出基于程序蓝图模型层次的重构。考虑到UML模型直观性的特点,给出UML类图模型在系统体系结构上的重构操作和实例,为重构在软件框架结构上的实施提供有力的支持。深入研究过程蓝图模型使用树形结构来描述程序的方法,定义过程蓝图相关重构操作并给出具体操作实例及过程,最后从过程蓝图模型生成新的源码。实验结果表明,UML模型和过程蓝图模型层次上的重构,提高了重构的抽象级别和效率。该方法能有效支持复杂软件的重构,并减少出错率。
重构UML模型过程蓝图模型程序模型
当软件所处的环境发生变化或者需求改变时,软件需要不断地增强、修改以适应新的变化,在这个发展的过程中,程序代码会变得越来越复杂,并且可能会偏离最初的设计意图,因而导致软件的质量持续降低。正是由于这个原因,软件开发的大量成本都花费在软件的维护上。随着软件系统的演变,系统的结构越来越复杂,性能越来越差,为解决这一问题,重构技术开始产生并得到发展。“重构”一词最早是由Opdyke[1]提出,他把重构定义为“面向对象领域的行为保持的重建的变体”。重构没有统一的定义,一个被广泛认可的定义是Martin Fowler[2]给出的定义,他把重构定义为动词和名词两种形式。“重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。重构(动词):使用一系列重构的手法,在不改变软件可观察行为的前提下,调整其结构。”
目前的重构技术的对象主要集中在程序源码上,属于代码级别重构,重构之前需要先对源码分析,进行重构定位,然后才能执行重构。UML模型的出现将重构提升到模型级别,UML模型重构的研究国内外已有较好进展,并且有一些工具能够支持UML模型的重构,在文献[3]的关于UML模型在模型驱动软件开发中的调查中,我们可以看到近期关于UML模型重构的部分研究成果。Sunye等[4]使用UML类图和状态图向我们展示了最初的模型重构,在元模型级别上定义为OCL约束,使用前置条件和后置条件来保证重构前后的行为保持,以此来提高模型的质量。Dobrzanski等[5]为可执行的UML类图模型中的坏味道提供了一系列重构,并在Telelogic TAU CASE工具中给出了实现。Tom Mens等[6,7]把重构提升到一个更高的抽象层次——基于模型驱动的软件重构,包括UML类图模型层次的重构等。文献[6]中使用UML协议的状态机和顺序图向我们提出了一种模型重构的形式化方法。文献[7]中Mens采用最先进的模型驱动软件开发工具AndroMDA进行案例开发的形式来解决模型驱动软件重构的一系列问题(如:如何定义、检测、保证模型质量,如何进行行为保持)。Wüst[8]开发的用于UML的软件质量评估工具,可以用来分析UML模型的结构,运用设计规则检测设计的不一致性和不完整性。El-Sharqwi[9]等人提出了一种基于使用XML语义定义的设计模式的UML模型重构。Reimann[10]等人提出了一种由角色模型和通用转换规则组成通用的UML模型重构框架。张雨薇[11]结合Opdyke和Fowler的研究和UML类图特点,将基本重构划分了三个层次,并给出UML自动重构的实现框架。国内外研究在UML模型重构上虽提出了相应的理论化方法、重构框架和重构工具支持,但是由于UML模型本身在程序过程描述方面没有较好的支持,所以我们使用过程蓝图模型弥补了UML模型在实现层过程描述的不足使得模型重构能够在方法级别上执行,从而把重构的级别提升到模型级与过程级。
2005年刘建宾[12]提出过程蓝图的概念并进行完备的形式化定义。2006年杨林邦[13]在基于源码重构的基础上提出了过程蓝图上的重构形式化定义,定义了37个过程蓝图模型重构的分析函数,在Opdyke[1]提出的7个不变量的基础上针对过程蓝图的特点增加了3个不变量,定义15个基本树变换操作,给出27个过程蓝图重构规格说明,并进行了一些简单的重构变换实践。2007年易长安[14]在文献[13]基础上进行了完善,新增15个过程蓝图模型重构的分析函数,提出3个新的不变量,增加5个基本树变换操作,又给出了9种重构规格说明并给出每种重构规格对应的源码重构实例。2011年梅新云[15]提出了一种程序模型重构的实现框架,使用JAVACC解析源码,从而实现源码到过程蓝图的逆向变换,重新定义了21种过程蓝图基本树变换函数,在文献[13]的基础上重新定义了3种重构规格说明,新增了15种重构分析函数,并添加了15种重构辅助函数,给出了增加和删除变量重构操作的实现算法和一个完整的变量重命名操作实现算法。2012年王俊飞[16]在C#过程蓝图上使用了基于数据流方程的切片算法,在文献[13-15]的基础上定义了9个新的分析函数,针对过程蓝图增加了3个新的重构操作。2013年胡伟奇[17]提出了一种Java蓝图模式的形式化定义框架,并引入了动作模式和过程模式,提出了一种新的Java蓝图模式匹配,包括结构匹配、语义匹配和参数匹配,并在这个的基础上说明了模式间的映射关系和重构变换规则。以上研究在过程蓝图模型重构研究方面做出了一定的理论成果,为进一步的研究提供了理论支持,但在过程蓝图上重构的方面尚未有深入涉及。
本文给出了一种新的程序蓝图框架,使用UML模型来表示系统的体系结构,定义UML类图重构操作,并给出操作实例,执行系统框架级的模型重构,为过程蓝图上的重构指明了方向。使用过程蓝图模型描述方法的实现,定义过程蓝图重构的一系列形式化操作,并给出部分操作实现,执行类的方法层次的重构,从而将重构提升到模型和过程级别。
我们把程序蓝图定义为UML类图模型、过程蓝图模型以及两者之间的关系。使用UML类图模型描述软件的体系结构框架,直观地呈现程序结构;使用过程蓝图模型描述程序方法的实现过程,直观地表示方法细节。故程序蓝图模型包括UML类图模型和过程蓝图模型两部分。
UML类图模型
Sunye等[4]第一次使用UML语言将重构思想应用到模型之上。UML模型,特别是UML的类图模型广泛得到研究者的论证,其优势是和面向对象程序的结构非常接近,因此,很多来自于面向对象程序(Fowler[2])的重构方法也可以转换成UML类图模型。使用UML模型重构的一个缺点是只能在程序框架上执行重构,在表示完整程序方面有所欠缺。
过程蓝图模型
过程蓝图是一种跨越分析、设计和构造阶段的统一过程表示方法,是描述软件行为过程的一种工程蓝图[12]。过程蓝图分为概念层、逻辑层和实现层三个层次,分别用于描述抽象概念结构(ACSD)、抽象逻辑结构(ALSD)和抽象实现结构(AISD)。过程蓝图提供了从概念层到逻辑层的控制流映射和从逻辑层到实现层的数据流映射,这种两级映射功能提供了一定程度的程序独立性(控制流独立性和数据流独立性)。过程蓝图的三层结构层层细化,逐步求精,是一种图形化的程序过程表示方法,是对源码进行描述的模型。其本质是抽象语法树,是一种内部外部统一表示的树形结构模型,富含丰富的语义,具备抽象语法树对重构的支持能力,将重构的抽象层次提高到模型级别。由于过程蓝图模型本身具备有效性、一致性、完备性、正确性,所以使用重构操作的执行更加容易,而且出错率较低,在一定程度上优于基于源码的重构和基于UML模型的重构。
UML类图模型和过程蓝图模型的关系
UML类图模型是程序框架级别的抽象,能够直观地呈现程序的体系结构。过程蓝图是类的方法级别的抽象,使用三层结构两级映射来描述方法实现过程。二者各有自己的优点和不足,一个完整的程序模型重构过程既需要框架层次的重构,又需要方法层次的重构,二者相辅相成缺一不可。
2.1UML类图三层重构操作扩展
UML类图上的重构分为基本重构和组合重构。基本重构是进行UML类图变换的一系列基本的操作,组合重构是将基本重构按照循序、选择和循环三种方式组合的一起完成实现一个重构的功能。文献[11,14]中给出将基本重构划分为三个层次:变量和对象级别的重构、构造函数和方法级别的重构、类和接口级别的重构,并给出每个层次下的重构操作的定义。
我们在该研究的基础上进行扩充和完善,提出以下新的UML类图模型的重构操作,并给出部分UML类图的基本重构和组合重构的实现实例。
(1) 新增变量和对象级别的重构操作
针对UML类图中的字段、临时变量以及对象进行的重构操作,新增以下重构操作:
Void EncapsulateField(Class c, Field varName ) 封装类的字段
Void SplitTempVariable(Class c, Field varName)针对每次不同赋值,创造一个独立、对应的临时变量
(2) 新增构造函数和方法级别的重构操作
针对UML类图中的字段、临时变量以及对象进行的重构操作,新增以下重构操作:
Void EncapsulateCollection(Class c, Set method1, Set method2)封装集合副本做返回值,增加新增和移除集合元素的函数
Void HideMethod(Class c,Method m)隐藏函数,将函数的类型改为private
Void AddParameter(Class c, Method m)为函数添加新的参数
Void RemoveParameter(Class c, Method m)移除函数的部分参数
(3) 新增类和接口级别的重构操作
针对UML类图中的字段、临时变量以及对象进行的重构操作,新增以下重构操作:
Void ReplaceValuewithObject(Class c1, Class c2, Object obj)新增类将数据项变为对象
Void Replace Constructor with Factory Method(Class c, Class c1, Class c2,FactoryMethod fm)为每个子类建立工厂函数
Void ExtractInterface(Interface,Class)将相同的子集提炼到一个独立的接口中
2.2UML类图重构操作实例
对类图的重构有五种基本类型操作:增加、删除、移动、泛化和特化。其中,泛化和特化分别是在类和接口的层次上进行上移和下移的重构操作。
实例源于文献[2]中的影片出租程序,并在其基础上进行适当扩展。顾客可以通过该系统租用不同的影片,系统可根据影片租用时间和影片类型计算费用并打印详单,亦可为常客计算积分。
实例1Void EncapsulateField(Class c, Field varName )
功能:将类c(Movie)的字段varName(price)进行封装。
重构类型:基本重构。
重构过程:Movie类中的字段price为public类型,不符合面向对象封装原则。首先为price字段添加get和set方法,然后更新price字段的所有引用,最后更改price的类型为private。如图1所示。
图1 EncapsulateField重构执行前后类图对比
实例2Void Extract_Class(Class c, Class c1)
重构类型:组合重构。
重构过程:重构之前Customer类有3个字段一个方法,经过分析之后,可以把其中的两个字段和一个方法使用Move_Field和Move_Method进行搬移到新类的重构,做法是首先新建一个TelephoneNumber类,然后运用Move_Field把areaCode和number字段搬移到TelephoneNumber类,然后使用Move_Method将getTelephoneNumber方法搬移到TelephoneNumber类,最后在调整可见性,重构执行前后的类图如图2所示。
图2 Extract_Class重构执行前后类图对比
实例3void ReplaceSubclasswithFields(Class c, Class c1, Class c2, Field varName)
功能:在超类c(Customer)中添加字段varName(_code)取代子类c1(VIP),c2(NVIP),并销毁子类。
重构类型:组合重构。
重构过程:Customer类是抽象类,有两个子类VIP和NVIP,两个子类唯一区别就是以不同方式实现了Customer类所声明的getCode()方法,返回不同的常量,我们首先使用Replace Constructor with Factory Method重构,在Customer类中为每个子类建立对应的工厂函数,并将所有调用处的构造函数改为工厂函数,接着使用Add_Instance_Variable重构,在Customer类中添加两个字段。在使用Add_Method重构在Customer类添加构造函数,最后使用Remove_Method,Remove_Class删除VIP类和NVIP类。重构执行前后的类图如图3所示。
图3 ReplaceSubclasswithFields重构执行前后类图对比
以上三个UML重构实例分别是字段、方法和类三个层次的代表性实例,主要说明了重构操作实现的相关细节。UML类图模型重构对程序的框架结构执行了较好优化,虽没有涉及到具体的方法层次的重构,但还是为过程蓝图模型重构提供了良好的框架基础。
流行音乐已介入社会生活的各个领域,成为年轻人喜爱并热情参与的文化娱乐形式,它深刻影响着青少年人生观、价值观的形成。因此,随着国家新一轮课程改革的进一步深入、学校和教师拥有越来越多的课程自主权,教师可以在中学生音乐教育中根据学生的实际情况,适当引入一些艺术价值相对较高的流行音乐,教会学生鉴赏音乐的办法,提高他们的鉴赏能力、欣赏品味和审美能力,并以此为契机激发他们学习音乐的兴趣,扩大他们的音乐视野。
3.1过程蓝图的树形重构
• 过程蓝图的树形结构模型
一个标准的Java系统源码通常包含以下元素:包名(Package)、类名(Class)、方法名(Method)、属性名(Attribute),这些元素的命名应符合Java命名规范,过程蓝图的树形结构表示和软件系统源码是一一对应的,也包含以上四种元素。一个系统的过程蓝图树形结构的基本元素之间的关系图如图4所示。
图4 过程蓝图基本元素之间的关系图
ACSD是抽象概念结构图,ALSD是抽象逻辑结构图,AISD是抽象实现结构图,它们一起组成了过程蓝图中一个操作的过程蓝图三层结构模型。过程蓝图三层结构的思想和MDA的思想是吻合的,ACSD对应于MDA的平台无关模型PIM,是对程序的高度抽象描述,表达了程序的思想,与具体的实现技术和平台无关;ALSD也对应与MDA的PIM模型,是对ACSD的细化,使语义的表达更加明确,与具体的实现技术和平台无关;AISD对应于MDA的平台相关模型(PSM),是基于特定的变换格式对ALSD的转换,格式的要求较为严格,同特定的平台和实现技术密切相关。ALSD模型是代码生成的依据,代码质量好坏取决于ALSD的格式正确性。
过程蓝图模型动作语义[12]包括终结动作和复合动作,ACSD的构造类型集合表示为Tacsd={+,*,o,?,!,:,>,e,&,#},ALSD和AISD的构造类型相同,集合表示为:Talsd={SEQ,SYN,FOR,WHL,DOW,SWH,IFE,IFT,CAS,DFT,BLK,DCL,OPE,LAB,TRY,CAH,FNY,BRK,CON,CHR,RET,UND}=Taisd,我们对Java语言的过程蓝图动作语义的定义汇总如表1所示。
表1 过程蓝图三层动作语义表
过程蓝图的三层模型都是一个合法的树结构,每一层都必须满足同时满足以下三个条件,令T表示过程蓝图树,A表示T的节点集合,a表示T的一个结点,root表示根节点。
条件1T中有且只有一个根节点root,并且root没有父节点。
C1: root∈A(parent(T,root) = ∧ unique(T,root))
条件2T中除去根节点以外,其他的结点有且只有一个父节点。
C2: a∈A—{root}(|parent(T,a)| = 1)
条件3T中的任何结点都不能是自己的祖先。
C3: a∈A(a∉ancestor(T,a))
三个条件保证过程蓝图的三层结构图在任何时刻具有树形层次结构的强制性要求。
• 过程蓝图重构形式化
过程蓝图是程序模型的一种过程级描述,需要用到的程序及模型实体有:包(Package)、类(Class)、操作(Method)、属性(Attribute)、过程蓝图树(T)、抽象概念结构图(Tc)、抽象逻辑结构图(Tl)、抽象实现结构图(Ti)、结点(Node)、结点类型(NType)、语句块(Statement)、表达式(Expression)、变量(Variable)、常量(Constant)和参数(Parameter)。
分析函数是用来对程序进行分析的函数,任何重构操作必须在分析函数的基础上才能正确进行。Opdyke[1]将分析函数分为原始分析函数和导出分析函数。原始分析函数是粒度最小、不可分割、且能实现最基本功能的分析函数;导出分析函数是原始分析函数的叠加调用和组合,结构复杂且功能更加强大的分析函数。分析函数的主要功能是保证执行重构操作的前置条件和重构后的程序满足的后置条件。
文献[13-16]在Opdyke和Roberts[18]的基础上针对过程蓝图一共提出了76个分析函数,因所采用的语言和实现方法不同而有所差异,由于过程蓝图重构操作实例实现的需要,我们在他们工作的基础上提出部分新的分析函数。如表2所示。
表2 新增分析函数列表
不变量是重构变换过程中应该保持不变的量,Opdyke在面向对象程序重构中,使用前置条件来保护不变量,以确保重构前后程序的行为保持,Roberts又增加了后置条件来保障重构的行为保持。文献[13,14,16]在Opdyke提出的7个不变量的基础上,针对过程蓝图的特点一共新增了9个不变量,我们根据过程蓝图上重构实现需要,增加新的不变量,来保证我们的重构结果的正确性。表3给出了新增不变量的列表。
表3 新增不变量列表
续表3
在过程蓝图中,所有的重构操作都是基于过程蓝图树结构的变换操作,因此,基本树变换操作是实现过程蓝图重构的基础。文献[13,14]给出了20个基本的树变换操作,我们在他们的基础上进行了扩充,新增了10个基本树变换操作。新增的基本树变换操作如表4所示。
表4 新增基本树变换操作列表
表4中S表示结构操作,N表示结点操作。
文献[13,14,16]在Martin Fowler提出70多种基于源码的重构操作的基础上,先后一共定义了39种过程蓝图上的重构规格说明,在他们的基础上,基于过程蓝图重构实现的需要,我们新增了10个重构操作,如表5所示。
表5 新增重构操作规格说明及分类
续表5
表5中RP为原子重构,R1为组合重构,R2为复杂重构;SR为结构重构,NR为结点重构。ACR为抽象概念层重构,ALR为抽象逻辑层重构,AIR为抽象实现层重构。
过程蓝图的树形结构模型的定义以及重构形式化工作的扩展,都是为过程蓝图上重构操作的具体实现做理论准备,下面我们将基于几种特定的应用场景,给出对应的重构操作在过程蓝图上的实现。
3.2过程蓝图重构操作实例
过程蓝图模型的构建使用了我们的蓝图工具,中文化蓝图模型的建立需要定义中英文映射表mapping.zhb和tokens.sys英文变量符号表,使用过程这里不再详述,可参见文献[12],在执行重构之前须确保中文化的过程蓝图模型能正确生成重构前的源代码。以下实例同样采用2.2节案例中提到的影片出租程序,展示了扩展后的重构形式化定义在过程蓝图模型重构操作中的具体应用,并给出详细的操作过程。
实例1:
重构操作:提炼方法ExtractMethod(Class c, Method m, Tl t, Statement s, Method m1)
功能:针对类c的方法m(printInfo)的过程蓝图t,将t的语句块s提炼为新的方法m1(printDetail)。
场景:Martin Fowler提出的22种代码坏味道中,重复代码、过长函数、过大的类、依恋情结、Switch语句等都是考虑执行Extract Method的外在表现,场景重前的源码和构造的过程蓝图模型如图5所示。
图5 重构前ExtractMethod类的方法源码和过程蓝图模型
执行步骤:
(1) 运用已定义的导出分析函数LongMethodWithoutTempVar及其他原始分析函数,分析重构的前置条件和不变量是否满足。
(2) 对“打印信息”过程蓝图模型进行基本树变换操作。选定“打印横幅”,执行InsertElderBrother插入兄长“打印详细信息”,并建立三层模型。跳转步骤5。
(3) 在类上执行CreateMethod添加新的方法“打印详细信息”,接着执行EditPBTree建立该方法的过程蓝图模型。然后连续使用CreateNode将“打印信息”蓝图模型中需要提炼的语句块依次添加到“打印详细信息”三层模型中。跳转步骤5。
(4) 打开“打印信息”过程蓝图模型,执行DeleteNode删除已提炼到“打印详细信息”蓝图模型中的所有节点。跳转到步骤5。
(5) 执行GenerateEnglishCode生成重构后英文源码,源码有错误,返回步骤2-步骤4。直到最终源码正确,重构结束。
重构结果:
重构执行后,从“打印信息”的语句块中提炼出了一个新方法“打印详细信息”,重构后的两个方法的过程蓝图模型和源码如图6所示。
图6 重构后Extract Method的的方法源码和过程蓝图模型
实例2:
重构操作:搬移函数MoveMethod(Class c1, Method m1, Class c2, Method m2)
功能:将类c1(Customer)中的方法m1(overRentCharge)搬移到类c2(CustomerType)中成为新的方法m2(overRentCharge)
场景:一个类中的方法有太多的行为与另外一个类相关而形成了高度耦合,就要考虑使用搬移函数MoveMethod,场景重构前的类框架和方法rentCharge,overRentCharge的过程蓝图模型如图7所示。
图7 Move Method重构之前的类框架和方法过程蓝图模型
执行步骤:
(1) 运用已定义的导出分析函数MethodAppear及其他原始分析函数,分析重构的前置条件和不变量是否满足。
(2) 在方法rentCharge和方法上overRentCharge上执行一系列树变换操作。先执行CreateTree分别建立过程蓝图树,然后执行InsertChild、InsertElderBrother,每次建立一个结点,执行UpdateNode进行更新保存。当所有的模型建立完毕之后执行savePBModel保存当前的过程蓝图模型。跳转到步骤5。
(3) 在类Customer中的方法overRentCharge上执行copyMethod操作,然后在CustomerType类中执行pasteMethod操作,这样两个类中都有方法overRentCharge。接着执行MethodAppear查找overRentCharge出现的类,如果只有在Customer中调用了,可以直接对Customer中的overRentCharge执行deleteMethod,删除该方法,并更新rentCharge的过程蓝图模型为方法调用。如果还有其他类调用Customer中的overRentCharge方法,可以在过程蓝图中使用deleteAllChildren删除overRentCharge的方法体,并执行InsertChild添加新子节点,加入对_type. overRentCharge()的调用。跳转到步骤5。
(4) 在类CustomerType的方法overRentCharge上执行EditPBTree,编辑过程蓝图模型,修改结点的调用语句,并执行UpdateNode更新结点和savePBModel保存模型,跳转到步骤5。
(5) 执行GenerateEnglishCode生成重构后英文源码,源码有错误,返回步骤2-步骤4。直到最终源码正确,重构结束。
重构结果:
重构完成后,删除了Customer类的overdraftCharge方法,在CustomerType类中添加了新的overdraftCharge方法,并进行了简单的修改,重构后的两个类的两个方法的过程蓝图模型和类框架如图8所示。
图8 Move Method重构之后的类框架和方法过程蓝图模型
实例1和实例2的结果分别说明重构形式化定义在简单和复杂的过程蓝图模型重构中是可以正确操作的,为以后重构系统的实现奠定了形式化基础。
程序模型重构的实现,需要建立UML模型、过程蓝图模型和程序源码的一致性映射,程序源码是基于文本的表示方法,UML模型和过程蓝图模型都是基于可视化图形的表示方法,比起文本表示更直观。源码到UML模型的逆向映射可以借助于许多开源工具(如ArgoUML)自动变换,也可以手工添加;程序源码到过程蓝图模型的转换需要使用过程蓝图模型转换工具自动转换,然后加以修改。重构完毕后UML模型可以正向生成框架代码,过程蓝图模型可以直接生成完整的可执行代码。下面给出程序模型重构实现的工作流程图,如图9所示。
图9 程序模型重构实现的工作流程图
上述框架的实现主要包括以下几步:
(1) 程序源码到程序模型的逆向变换
程序模型包括UML模型和过程蓝图模型,源码到模型的变换需要遵循特定的映射规则,首先,借助于开源的UML建模工具和过程蓝图变换系统,实现半自动化的变换,生成初步的UML类图模型和每个方法对应的过程蓝图模型,然后人工在模型上进行修改,以保证变换后模型的正确性。
(2) UML类图模型的重构
UML类图模型的重构在类、方法、属性三个层次上执行。首先对UML类图运用分析函数确保前置条件满足,然后执行类图重构操作,最后通过分析函数验证后置条件和不变量是否满足,是则结束,否则撤销。
(3) 过程蓝图模型的重构
过程蓝图的重构执行之前使用分析函数进行模型的分析,在满足前置条件的前提下执行重构操作,使用不变量来进行行为保持验证,运用树变换操作来修改过程蓝图的三层模型,最后使用重构变换系统执行模型重构变换,重构变换系统需要分析函数、基本树变换,重构规格说明的支撑。使用重构变换系统改变后的过程蓝图模型只有满足后置条件和不变量才算是正确的重构。
(4) 程序模型到程序源码的正向变换
UML模型和过程蓝图模型执行重构操作之后,借助于UML建模工具和过程蓝图变换系统,都可以正向生成程序源码,从UML模型生成的是程序的框架代码,有利于对程序的基本结构进行把握。从过程蓝图模型生成可执行的源码,可以直接在开发平台中进行调试验证。
为了验证程序模型重构实现框架的可行性,UML类图重构操作的正确性,过程蓝图重构形式化定义的正确性,过程蓝图模型重构的优越性,我们同样采用2.2节案例中提到的影片出租程序进行实现。
5.1程序源码重构执行过程
分解并重组Customer类的过长方法statement()
(1) 运用ExtractMethod()重构将statement()中的switch代码块抽取成amountFor()方法,并在statement方法添加引用,thisAmount = amountFor(each)。
(2) amountFor()方法的某些变量名称无意义,使用Rename()重构将这些变量重命名,分析amountFor()方法时发现,使用了来自Rental类的信息,没有使用Customer类的信息,故需要运用MoveMethod()重构将amountFor()方法搬移到Rental类中,再运用Rename()重构将amountFor()重命名为getCharge(),最后更新statement()方法中对旧函数的所有引用,修改为:thisAmount = each.getCharge()。
(3) 这时我们发现临时变量thisAmount多余了,运用ReplaceTempwithQuery()重构将thisAmount去除,只需将thisAmount的引用全部替换成getCharge()。
(4) 使用类似(1)(2)(3)的方法,使用ExtractMethod重构将“常客积分计算”代码抽取为方法getFrequentRenterPoints(),然后替换引用为frequentRenterPoints += each.getFrequentRenterPoints()。
(5) 连续两次交替使用ReplaceTempwithQuery和ExtractMethod和重构,在类Customer中提取出两个方法getTotalCharge()和getTotalFrequentRenterPoints(),替换掉临时变量totalAmount和frequentRenterPoints的引用,去除临时变量。
5.2UML类图模型重构执行过程
这里只给出重要属性的UML类图,并借此来说明UML类图重构实现的过程。
(1) 分析源程序,构造UML类图模型,重构操作执行之前UML类图模型如图10所示。
图10 初始程序的UML类图
(2) 重构分解并重组Customer类的过长方法statement(),顺序执行UML类图基本重构操作ExtractMethod(),MoveMethod()和Rename(),得到如图11所示的UML类图。
图11 抽取并移动getChange()方法后UML类图
(3) 再次顺序执行和(2)中相同的3种UML类图基本重构操作,得到如图12所示UML类图。
图12 抽取并移动getFrequentRenterPoints()方法后UML类图
(4) 最后连续两次顺序交替使用UML类图的基本重构操作ExtractMethod()和ReplaceTempwithQuery(),最终得到如图13所示的UML类图。
图13 重构完成后的UML类图
5.3过程蓝图模型重构执行过程
UML类图模型重构的直观性框架为过程蓝图模型重构在方法具体实现上提供了很好的指导。下面我们将以类图模型重构过程为基础,展示过程蓝图模型重构在方法级别的实现过程。
(1) 使用过程蓝图工具自动化生成过程蓝图模型,并构造中英文映射表和tokens,重构之前的statement()方法的过程蓝图模型M的三层结构分别如图14-图16所示。
图14 重构前statement()方法的抽象概念结构图-ACSD
图15 重构前statement()方法的抽象逻辑结构图-ALSD
图16 重构前statement()方法的抽象实现结构图-AISD
(2) 首先,在statemment()方法的过程蓝图模型M中对switch代码段对应的三层蓝图模型执行ExtractMethod()重构,提取新的方法amountFor()的过程蓝图模型M1,接着使用MoveMethod()重构将M1搬移到Rental类中,成为新的过程蓝图模型M2,然后使用Rename()重构将M2描述的方法amountFor()重命名为getCharge(),更新M中的引用。其次,使用相同方法对M中“常客积分计算”对应的三层蓝图模型执行重构,最终在Rental类建立getFrequentRenterPoints()对应的过程蓝图模型M3,并在M中更新对M3的引用。最后,在上面的基础上,连续两次顺序交替使用过程蓝图重构操作ReplaceTempwithQuery()和ExtractMethod(),在Customer类中建立两个新的过程蓝图模型M4和M5,M4描述方法getTotalCharge(),M5描述方法getTotalFrequentRenterPoints()。重构完成之后各个方法所对应的过程蓝图模型分别如图17-图21所示。
图17 重构后Renter类的方法getFrequentRenterPoints()的过程蓝图模型
图18 重构后Customer类的方法statement()的过程蓝图模型
图19 重构后Customer类方法getTotalFrequentRenterPoints()过程蓝图模型
图20 重构后Customer类的方法getTotalCharge()的过程蓝图模型
图21 重构后Renter类的方法getCharge()的过程蓝图模型
通过比较可以看出源码重构的可读性差,难以找到需要重构的地方,而且容易出错;UML类图重构直观性好,效率高,但只能进行类模型框架重构;而过程蓝图重构弥补了UML模型不能执行过程级别重构的缺点,并且蓝图模型与源码一一对应使得程序更易于理解,提高了重构的效率和程序的可读性。
本文研究了重构操作在程序模型级别上的执行实例,使用UML类图执行程序框架级别的重构变换,运用过程蓝图模型描述类的方法实现,执行方法级别的重构变换。
本文的贡献主要包括:
• 在属性、方法、类三个层次上定义了新的类图基本重构操作。
• 给出三种代表性类图模型基本和组合重构操作实例。
• 完善过程蓝图模型重构的形式化定义,新增分析函数、不变量、基本树变换操作、重构规格说明定义。
• 给出两种代表性的简单和复杂过程蓝图模型重构操作实例。
• 给出一种程序蓝图模型重构的实现框架。
• 进行了源码重构、UML类图重构,过程蓝图模型重构实验验证与比较。
程序蓝图重构实现框架有待于进一步在大型的软件系统中进行验证,今后的工作中我们将进一步完善过程蓝图工具对模型重构变换的支持,最终给出一套具有较高价值的模型重构方法和工具。
[1] Opdyke W F. Refactoring: A program restructuring aid in designing object-oriented application frameworks[D]. PhD thesis, University of Illinois at Urbana-Champaign, 1992.
[2] Fowler M. Refactoring: improving the design of existing code[M]. Pearson Education India, 1999.
[3] Khalil A, Dingel J. Supporting the evolution of UML models in model driven software developmeny: A Survey[R]. Technical Report, School of Computing, Queen’s University, Canada, 2013.
[4] Sunyé G, Pollet D, Le Traon Y, et al. Refactoring UML models[M].in UML 2001—The Unified Modeling Language. Modeling Languages, Concepts, and Tools. Springer Berlin Heidelberg, 2001:134-148.
[6] Van Der Straeten R, Jonckers V, Mens T. A formal approach to model refactoring and model refinement[J]. Software & Systems Modeling, 2007, 6(2): 139-162.
[7] Mens T, Taentzer G, Müller D. Model-driven Software Refactoring[C]//WRT. 2007: 25-27.
[8] Wüst.SDMetrics V2.31[EB/OL]. http://www.sdmetrics.com/, latest released: July 3,2013.
[9] El Sharqwi M, Mahdi H, El Madah I. Pattern-based model refactoring[C]//Proceedings of Computer Engineering and Systems (ICCES), 2010 International Conference on. IEEE, 2010:301-306.
[10] Reimann J, Seifert M, Aβmann U. On the reuse and recommendation of model refactoring specifications[J]. Software & Systems Modeling, 2013, 12(3): 579-596.
[11] 张雨薇, 候少杰. 基于 UML 自动化重构工具的研究[J]. 计算机与信息技术,2005(5):32-37.
[12] 刘建宾.过程蓝图设计方法学[M].北京:科学出版社,2005.
[13] 杨林邦. 基于过程蓝图的重构研究[D]. 汕头大学,2006.
[14] 易长安. 基于类图和过程蓝图的模型重构操作的研究[D]. 汕头大学,2007.
[15] 梅新云. 程序模型重构实现方法与工具[D]. 北京信息科技大学,2011.
[16] 王俊飞. 程序模型再工程方法及其支撑工具研究[D]. 北京信息科技大学,2012.
[17] 胡伟奇. JAVA蓝图模式及其重构方法研究[D]. 北京信息科技大学,2013.
[18] Roberts D B, Johnson R. Practical analysis for refactoring[M].University of Illinois at Urbana-Champaign,1999.
RESEARCH ON REFACTORING OPERATION EXAMPLES OF PROGRAM BLUEPRINT MODEL
Liang PengjuLiu JianbinZheng Liwei
(SchoolofComputerScience,BeijingInformationScienceandTechnologyUniversity,Beijing100101,China)
Refactoring is a technique to improve the comprehensibility and maintainability of software systems by changing their internal structure without altering their external behavioural properties. Although traditional source-level refactoring has been supported by a lot of refactoring tools, the refactoring of complex software is very difficult and is prone to error. In view of this situation, we put forward a program blueprint model hierarchy-based refactoring. Taking into account the intuitive feature of a UML model, we proposed the refactoring operations and implementation examples of UML class diagram model on system architecture. These operations provide a strong support for the refactoring implemented on software framework architecture. We have researched deeply the method of procedure blueprint model using a tree structure to describe the program, and defined in this paper the refactoring operations correlated to procedure blueprint as well as showed some specific examples and procedures of these refactoring operations. Finally, from the procedure blueprint model the new source codes can be generated. Experimental results showed that the refactoring on UML model and procedure blueprint model hierarchy improves the abstraction level and efficiency of refactoring. This method can effectively support the refactoring of complex software and reduce the error rate.
RefactoringUML modelProcedure blueprint modelProgram model
2014-07-15。
北京市教委人才培养模式创新实验区项目(京教函[2009]630号);北京市教委科技计划面上项目(KM201311232013)。
梁朋举,硕士生,主研领域:模型驱动架构,过程蓝图。刘建宾,教授。郑丽伟,讲师。
TP311
A
10.3969/j.issn.1000-386x.2016.03.005