梁朋舉 劉建賓 鄭麗偉
(北京信息科技大學計算機學院 北京 100101)
?
程序藍圖模型重構(gòu)操作實例研究
梁朋舉劉建賓鄭麗偉
(北京信息科技大學計算機學院北京 100101)
重構(gòu)可以改善軟件系統(tǒng)的內(nèi)部結(jié)構(gòu),提高軟件可理解性、可維護性,而又不改變軟件的外部行為。傳統(tǒng)的源碼層次的重構(gòu)雖有很多重構(gòu)工具的支持,但是對于復雜軟件的重構(gòu)難度大,容易出錯。針對這種情況,提出基于程序藍圖模型層次的重構(gòu)??紤]到UML模型直觀性的特點,給出UML類圖模型在系統(tǒng)體系結(jié)構(gòu)上的重構(gòu)操作和實例,為重構(gòu)在軟件框架結(jié)構(gòu)上的實施提供有力的支持。深入研究過程藍圖模型使用樹形結(jié)構(gòu)來描述程序的方法,定義過程藍圖相關(guān)重構(gòu)操作并給出具體操作實例及過程,最后從過程藍圖模型生成新的源碼。實驗結(jié)果表明,UML模型和過程藍圖模型層次上的重構(gòu),提高了重構(gòu)的抽象級別和效率。該方法能有效支持復雜軟件的重構(gòu),并減少出錯率。
重構(gòu)UML模型過程藍圖模型程序模型
當軟件所處的環(huán)境發(fā)生變化或者需求改變時,軟件需要不斷地增強、修改以適應(yīng)新的變化,在這個發(fā)展的過程中,程序代碼會變得越來越復雜,并且可能會偏離最初的設(shè)計意圖,因而導致軟件的質(zhì)量持續(xù)降低。正是由于這個原因,軟件開發(fā)的大量成本都花費在軟件的維護上。隨著軟件系統(tǒng)的演變,系統(tǒng)的結(jié)構(gòu)越來越復雜,性能越來越差,為解決這一問題,重構(gòu)技術(shù)開始產(chǎn)生并得到發(fā)展?!爸貥?gòu)”一詞最早是由Opdyke[1]提出,他把重構(gòu)定義為“面向?qū)ο箢I(lǐng)域的行為保持的重建的變體”。重構(gòu)沒有統(tǒng)一的定義,一個被廣泛認可的定義是Martin Fowler[2]給出的定義,他把重構(gòu)定義為動詞和名詞兩種形式。“重構(gòu)(名詞):對軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。重構(gòu)(動詞):使用一系列重構(gòu)的手法,在不改變軟件可觀察行為的前提下,調(diào)整其結(jié)構(gòu)?!?/p>
目前的重構(gòu)技術(shù)的對象主要集中在程序源碼上,屬于代碼級別重構(gòu),重構(gòu)之前需要先對源碼分析,進行重構(gòu)定位,然后才能執(zhí)行重構(gòu)。UML模型的出現(xiàn)將重構(gòu)提升到模型級別,UML模型重構(gòu)的研究國內(nèi)外已有較好進展,并且有一些工具能夠支持UML模型的重構(gòu),在文獻[3]的關(guān)于UML模型在模型驅(qū)動軟件開發(fā)中的調(diào)查中,我們可以看到近期關(guān)于UML模型重構(gòu)的部分研究成果。Sunye等[4]使用UML類圖和狀態(tài)圖向我們展示了最初的模型重構(gòu),在元模型級別上定義為OCL約束,使用前置條件和后置條件來保證重構(gòu)前后的行為保持,以此來提高模型的質(zhì)量。Dobrzanski等[5]為可執(zhí)行的UML類圖模型中的壞味道提供了一系列重構(gòu),并在Telelogic TAU CASE工具中給出了實現(xiàn)。Tom Mens等[6,7]把重構(gòu)提升到一個更高的抽象層次——基于模型驅(qū)動的軟件重構(gòu),包括UML類圖模型層次的重構(gòu)等。文獻[6]中使用UML協(xié)議的狀態(tài)機和順序圖向我們提出了一種模型重構(gòu)的形式化方法。文獻[7]中Mens采用最先進的模型驅(qū)動軟件開發(fā)工具AndroMDA進行案例開發(fā)的形式來解決模型驅(qū)動軟件重構(gòu)的一系列問題(如:如何定義、檢測、保證模型質(zhì)量,如何進行行為保持)。Wüst[8]開發(fā)的用于UML的軟件質(zhì)量評估工具,可以用來分析UML模型的結(jié)構(gòu),運用設(shè)計規(guī)則檢測設(shè)計的不一致性和不完整性。El-Sharqwi[9]等人提出了一種基于使用XML語義定義的設(shè)計模式的UML模型重構(gòu)。Reimann[10]等人提出了一種由角色模型和通用轉(zhuǎn)換規(guī)則組成通用的UML模型重構(gòu)框架。張雨薇[11]結(jié)合Opdyke和Fowler的研究和UML類圖特點,將基本重構(gòu)劃分了三個層次,并給出UML自動重構(gòu)的實現(xiàn)框架。國內(nèi)外研究在UML模型重構(gòu)上雖提出了相應(yīng)的理論化方法、重構(gòu)框架和重構(gòu)工具支持,但是由于UML模型本身在程序過程描述方面沒有較好的支持,所以我們使用過程藍圖模型彌補了UML模型在實現(xiàn)層過程描述的不足使得模型重構(gòu)能夠在方法級別上執(zhí)行,從而把重構(gòu)的級別提升到模型級與過程級。
2005年劉建賓[12]提出過程藍圖的概念并進行完備的形式化定義。2006年楊林邦[13]在基于源碼重構(gòu)的基礎(chǔ)上提出了過程藍圖上的重構(gòu)形式化定義,定義了37個過程藍圖模型重構(gòu)的分析函數(shù),在Opdyke[1]提出的7個不變量的基礎(chǔ)上針對過程藍圖的特點增加了3個不變量,定義15個基本樹變換操作,給出27個過程藍圖重構(gòu)規(guī)格說明,并進行了一些簡單的重構(gòu)變換實踐。2007年易長安[14]在文獻[13]基礎(chǔ)上進行了完善,新增15個過程藍圖模型重構(gòu)的分析函數(shù),提出3個新的不變量,增加5個基本樹變換操作,又給出了9種重構(gòu)規(guī)格說明并給出每種重構(gòu)規(guī)格對應(yīng)的源碼重構(gòu)實例。2011年梅新云[15]提出了一種程序模型重構(gòu)的實現(xiàn)框架,使用JAVACC解析源碼,從而實現(xiàn)源碼到過程藍圖的逆向變換,重新定義了21種過程藍圖基本樹變換函數(shù),在文獻[13]的基礎(chǔ)上重新定義了3種重構(gòu)規(guī)格說明,新增了15種重構(gòu)分析函數(shù),并添加了15種重構(gòu)輔助函數(shù),給出了增加和刪除變量重構(gòu)操作的實現(xiàn)算法和一個完整的變量重命名操作實現(xiàn)算法。2012年王俊飛[16]在C#過程藍圖上使用了基于數(shù)據(jù)流方程的切片算法,在文獻[13-15]的基礎(chǔ)上定義了9個新的分析函數(shù),針對過程藍圖增加了3個新的重構(gòu)操作。2013年胡偉奇[17]提出了一種Java藍圖模式的形式化定義框架,并引入了動作模式和過程模式,提出了一種新的Java藍圖模式匹配,包括結(jié)構(gòu)匹配、語義匹配和參數(shù)匹配,并在這個的基礎(chǔ)上說明了模式間的映射關(guān)系和重構(gòu)變換規(guī)則。以上研究在過程藍圖模型重構(gòu)研究方面做出了一定的理論成果,為進一步的研究提供了理論支持,但在過程藍圖上重構(gòu)的方面尚未有深入涉及。
本文給出了一種新的程序藍圖框架,使用UML模型來表示系統(tǒng)的體系結(jié)構(gòu),定義UML類圖重構(gòu)操作,并給出操作實例,執(zhí)行系統(tǒng)框架級的模型重構(gòu),為過程藍圖上的重構(gòu)指明了方向。使用過程藍圖模型描述方法的實現(xiàn),定義過程藍圖重構(gòu)的一系列形式化操作,并給出部分操作實現(xiàn),執(zhí)行類的方法層次的重構(gòu),從而將重構(gòu)提升到模型和過程級別。
我們把程序藍圖定義為UML類圖模型、過程藍圖模型以及兩者之間的關(guān)系。使用UML類圖模型描述軟件的體系結(jié)構(gòu)框架,直觀地呈現(xiàn)程序結(jié)構(gòu);使用過程藍圖模型描述程序方法的實現(xiàn)過程,直觀地表示方法細節(jié)。故程序藍圖模型包括UML類圖模型和過程藍圖模型兩部分。
UML類圖模型
Sunye等[4]第一次使用UML語言將重構(gòu)思想應(yīng)用到模型之上。UML模型,特別是UML的類圖模型廣泛得到研究者的論證,其優(yōu)勢是和面向?qū)ο蟪绦虻慕Y(jié)構(gòu)非常接近,因此,很多來自于面向?qū)ο蟪绦?Fowler[2])的重構(gòu)方法也可以轉(zhuǎn)換成UML類圖模型。使用UML模型重構(gòu)的一個缺點是只能在程序框架上執(zhí)行重構(gòu),在表示完整程序方面有所欠缺。
過程藍圖模型
過程藍圖是一種跨越分析、設(shè)計和構(gòu)造階段的統(tǒng)一過程表示方法,是描述軟件行為過程的一種工程藍圖[12]。過程藍圖分為概念層、邏輯層和實現(xiàn)層三個層次,分別用于描述抽象概念結(jié)構(gòu)(ACSD)、抽象邏輯結(jié)構(gòu)(ALSD)和抽象實現(xiàn)結(jié)構(gòu)(AISD)。過程藍圖提供了從概念層到邏輯層的控制流映射和從邏輯層到實現(xiàn)層的數(shù)據(jù)流映射,這種兩級映射功能提供了一定程度的程序獨立性(控制流獨立性和數(shù)據(jù)流獨立性)。過程藍圖的三層結(jié)構(gòu)層層細化,逐步求精,是一種圖形化的程序過程表示方法,是對源碼進行描述的模型。其本質(zhì)是抽象語法樹,是一種內(nèi)部外部統(tǒng)一表示的樹形結(jié)構(gòu)模型,富含豐富的語義,具備抽象語法樹對重構(gòu)的支持能力,將重構(gòu)的抽象層次提高到模型級別。由于過程藍圖模型本身具備有效性、一致性、完備性、正確性,所以使用重構(gòu)操作的執(zhí)行更加容易,而且出錯率較低,在一定程度上優(yōu)于基于源碼的重構(gòu)和基于UML模型的重構(gòu)。
UML類圖模型和過程藍圖模型的關(guān)系
UML類圖模型是程序框架級別的抽象,能夠直觀地呈現(xiàn)程序的體系結(jié)構(gòu)。過程藍圖是類的方法級別的抽象,使用三層結(jié)構(gòu)兩級映射來描述方法實現(xiàn)過程。二者各有自己的優(yōu)點和不足,一個完整的程序模型重構(gòu)過程既需要框架層次的重構(gòu),又需要方法層次的重構(gòu),二者相輔相成缺一不可。
2.1UML類圖三層重構(gòu)操作擴展
UML類圖上的重構(gòu)分為基本重構(gòu)和組合重構(gòu)。基本重構(gòu)是進行UML類圖變換的一系列基本的操作,組合重構(gòu)是將基本重構(gòu)按照循序、選擇和循環(huán)三種方式組合的一起完成實現(xiàn)一個重構(gòu)的功能。文獻[11,14]中給出將基本重構(gòu)劃分為三個層次:變量和對象級別的重構(gòu)、構(gòu)造函數(shù)和方法級別的重構(gòu)、類和接口級別的重構(gòu),并給出每個層次下的重構(gòu)操作的定義。
我們在該研究的基礎(chǔ)上進行擴充和完善,提出以下新的UML類圖模型的重構(gòu)操作,并給出部分UML類圖的基本重構(gòu)和組合重構(gòu)的實現(xiàn)實例。
(1) 新增變量和對象級別的重構(gòu)操作
針對UML類圖中的字段、臨時變量以及對象進行的重構(gòu)操作,新增以下重構(gòu)操作:
Void EncapsulateField(Class c, Field varName ) 封裝類的字段
Void SplitTempVariable(Class c, Field varName)針對每次不同賦值,創(chuàng)造一個獨立、對應(yīng)的臨時變量
(2) 新增構(gòu)造函數(shù)和方法級別的重構(gòu)操作
針對UML類圖中的字段、臨時變量以及對象進行的重構(gòu)操作,新增以下重構(gòu)操作:
Void EncapsulateCollection(Class c, Set method1, Set method2)封裝集合副本做返回值,增加新增和移除集合元素的函數(shù)
Void HideMethod(Class c,Method m)隱藏函數(shù),將函數(shù)的類型改為private
Void AddParameter(Class c, Method m)為函數(shù)添加新的參數(shù)
Void RemoveParameter(Class c, Method m)移除函數(shù)的部分參數(shù)
(3) 新增類和接口級別的重構(gòu)操作
針對UML類圖中的字段、臨時變量以及對象進行的重構(gòu)操作,新增以下重構(gòu)操作:
Void ReplaceValuewithObject(Class c1, Class c2, Object obj)新增類將數(shù)據(jù)項變?yōu)閷ο?/p>
Void Replace Constructor with Factory Method(Class c, Class c1, Class c2,FactoryMethod fm)為每個子類建立工廠函數(shù)
Void ExtractInterface(Interface,Class)將相同的子集提煉到一個獨立的接口中
2.2UML類圖重構(gòu)操作實例
對類圖的重構(gòu)有五種基本類型操作:增加、刪除、移動、泛化和特化。其中,泛化和特化分別是在類和接口的層次上進行上移和下移的重構(gòu)操作。
實例源于文獻[2]中的影片出租程序,并在其基礎(chǔ)上進行適當擴展。顧客可以通過該系統(tǒng)租用不同的影片,系統(tǒng)可根據(jù)影片租用時間和影片類型計算費用并打印詳單,亦可為??陀嬎惴e分。
實例1Void EncapsulateField(Class c, Field varName )
功能:將類c(Movie)的字段varName(price)進行封裝。
重構(gòu)類型:基本重構(gòu)。
重構(gòu)過程:Movie類中的字段price為public類型,不符合面向?qū)ο蠓庋b原則。首先為price字段添加get和set方法,然后更新price字段的所有引用,最后更改price的類型為private。如圖1所示。

圖1 EncapsulateField重構(gòu)執(zhí)行前后類圖對比
實例2Void Extract_Class(Class c, Class c1)
重構(gòu)類型:組合重構(gòu)。
重構(gòu)過程:重構(gòu)之前Customer類有3個字段一個方法,經(jīng)過分析之后,可以把其中的兩個字段和一個方法使用Move_Field和Move_Method進行搬移到新類的重構(gòu),做法是首先新建一個TelephoneNumber類,然后運用Move_Field把areaCode和number字段搬移到TelephoneNumber類,然后使用Move_Method將getTelephoneNumber方法搬移到TelephoneNumber類,最后在調(diào)整可見性,重構(gòu)執(zhí)行前后的類圖如圖2所示。

圖2 Extract_Class重構(gòu)執(zhí)行前后類圖對比
實例3void ReplaceSubclasswithFields(Class c, Class c1, Class c2, Field varName)
功能:在超類c(Customer)中添加字段varName(_code)取代子類c1(VIP),c2(NVIP),并銷毀子類。
重構(gòu)類型:組合重構(gòu)。
重構(gòu)過程:Customer類是抽象類,有兩個子類VIP和NVIP,兩個子類唯一區(qū)別就是以不同方式實現(xiàn)了Customer類所聲明的getCode()方法,返回不同的常量,我們首先使用Replace Constructor with Factory Method重構(gòu),在Customer類中為每個子類建立對應(yīng)的工廠函數(shù),并將所有調(diào)用處的構(gòu)造函數(shù)改為工廠函數(shù),接著使用Add_Instance_Variable重構(gòu),在Customer類中添加兩個字段。在使用Add_Method重構(gòu)在Customer類添加構(gòu)造函數(shù),最后使用Remove_Method,Remove_Class刪除VIP類和NVIP類。重構(gòu)執(zhí)行前后的類圖如圖3所示。

圖3 ReplaceSubclasswithFields重構(gòu)執(zhí)行前后類圖對比
以上三個UML重構(gòu)實例分別是字段、方法和類三個層次的代表性實例,主要說明了重構(gòu)操作實現(xiàn)的相關(guān)細節(jié)。UML類圖模型重構(gòu)對程序的框架結(jié)構(gòu)執(zhí)行了較好優(yōu)化,雖沒有涉及到具體的方法層次的重構(gòu),但還是為過程藍圖模型重構(gòu)提供了良好的框架基礎(chǔ)。
流行音樂已介入社會生活的各個領(lǐng)域,成為年輕人喜愛并熱情參與的文化娛樂形式,它深刻影響著青少年人生觀、價值觀的形成。因此,隨著國家新一輪課程改革的進一步深入、學校和教師擁有越來越多的課程自主權(quán),教師可以在中學生音樂教育中根據(jù)學生的實際情況,適當引入一些藝術(shù)價值相對較高的流行音樂,教會學生鑒賞音樂的辦法,提高他們的鑒賞能力、欣賞品味和審美能力,并以此為契機激發(fā)他們學習音樂的興趣,擴大他們的音樂視野。
3.1過程藍圖的樹形重構(gòu)
? 過程藍圖的樹形結(jié)構(gòu)模型
一個標準的Java系統(tǒng)源碼通常包含以下元素:包名(Package)、類名(Class)、方法名(Method)、屬性名(Attribute),這些元素的命名應(yīng)符合Java命名規(guī)范,過程藍圖的樹形結(jié)構(gòu)表示和軟件系統(tǒng)源碼是一一對應(yīng)的,也包含以上四種元素。一個系統(tǒng)的過程藍圖樹形結(jié)構(gòu)的基本元素之間的關(guān)系圖如圖4所示。

圖4 過程藍圖基本元素之間的關(guān)系圖
ACSD是抽象概念結(jié)構(gòu)圖,ALSD是抽象邏輯結(jié)構(gòu)圖,AISD是抽象實現(xiàn)結(jié)構(gòu)圖,它們一起組成了過程藍圖中一個操作的過程藍圖三層結(jié)構(gòu)模型。過程藍圖三層結(jié)構(gòu)的思想和MDA的思想是吻合的,ACSD對應(yīng)于MDA的平臺無關(guān)模型PIM,是對程序的高度抽象描述,表達了程序的思想,與具體的實現(xiàn)技術(shù)和平臺無關(guān);ALSD也對應(yīng)與MDA的PIM模型,是對ACSD的細化,使語義的表達更加明確,與具體的實現(xiàn)技術(shù)和平臺無關(guān);AISD對應(yīng)于MDA的平臺相關(guān)模型(PSM),是基于特定的變換格式對ALSD的轉(zhuǎn)換,格式的要求較為嚴格,同特定的平臺和實現(xiàn)技術(shù)密切相關(guān)。ALSD模型是代碼生成的依據(jù),代碼質(zhì)量好壞取決于ALSD的格式正確性。
過程藍圖模型動作語義[12]包括終結(jié)動作和復合動作,ACSD的構(gòu)造類型集合表示為Tacsd={+,*,o,?,!,:,>,e,&,#},ALSD和AISD的構(gòu)造類型相同,集合表示為:Talsd={SEQ,SYN,F(xiàn)OR,WHL,DOW,SWH,IFE,IFT,CAS,DFT,BLK,DCL,OPE,LAB,TRY,CAH,F(xiàn)NY,BRK,CON,CHR,RET,UND}=Taisd,我們對Java語言的過程藍圖動作語義的定義匯總?cè)绫?所示。

表1 過程藍圖三層動作語義表
過程藍圖的三層模型都是一個合法的樹結(jié)構(gòu),每一層都必須滿足同時滿足以下三個條件,令T表示過程藍圖樹,A表示T的節(jié)點集合,a表示T的一個結(jié)點,root表示根節(jié)點。
條件1T中有且只有一個根節(jié)點root,并且root沒有父節(jié)點。
C1: root∈A(parent(T,root) = ∧ unique(T,root))
條件2T中除去根節(jié)點以外,其他的結(jié)點有且只有一個父節(jié)點。
C2: a∈A—{root}(|parent(T,a)| = 1)
條件3T中的任何結(jié)點都不能是自己的祖先。
C3: a∈A(a?ancestor(T,a))
三個條件保證過程藍圖的三層結(jié)構(gòu)圖在任何時刻具有樹形層次結(jié)構(gòu)的強制性要求。
? 過程藍圖重構(gòu)形式化
過程藍圖是程序模型的一種過程級描述,需要用到的程序及模型實體有:包(Package)、類(Class)、操作(Method)、屬性(Attribute)、過程藍圖樹(T)、抽象概念結(jié)構(gòu)圖(Tc)、抽象邏輯結(jié)構(gòu)圖(Tl)、抽象實現(xiàn)結(jié)構(gòu)圖(Ti)、結(jié)點(Node)、結(jié)點類型(NType)、語句塊(Statement)、表達式(Expression)、變量(Variable)、常量(Constant)和參數(shù)(Parameter)。
分析函數(shù)是用來對程序進行分析的函數(shù),任何重構(gòu)操作必須在分析函數(shù)的基礎(chǔ)上才能正確進行。Opdyke[1]將分析函數(shù)分為原始分析函數(shù)和導出分析函數(shù)。原始分析函數(shù)是粒度最小、不可分割、且能實現(xiàn)最基本功能的分析函數(shù);導出分析函數(shù)是原始分析函數(shù)的疊加調(diào)用和組合,結(jié)構(gòu)復雜且功能更加強大的分析函數(shù)。分析函數(shù)的主要功能是保證執(zhí)行重構(gòu)操作的前置條件和重構(gòu)后的程序滿足的后置條件。
文獻[13-16]在Opdyke和Roberts[18]的基礎(chǔ)上針對過程藍圖一共提出了76個分析函數(shù),因所采用的語言和實現(xiàn)方法不同而有所差異,由于過程藍圖重構(gòu)操作實例實現(xiàn)的需要,我們在他們工作的基礎(chǔ)上提出部分新的分析函數(shù)。如表2所示。

表2 新增分析函數(shù)列表
不變量是重構(gòu)變換過程中應(yīng)該保持不變的量,Opdyke在面向?qū)ο蟪绦蛑貥?gòu)中,使用前置條件來保護不變量,以確保重構(gòu)前后程序的行為保持,Roberts又增加了后置條件來保障重構(gòu)的行為保持。文獻[13,14,16]在Opdyke提出的7個不變量的基礎(chǔ)上,針對過程藍圖的特點一共新增了9個不變量,我們根據(jù)過程藍圖上重構(gòu)實現(xiàn)需要,增加新的不變量,來保證我們的重構(gòu)結(jié)果的正確性。表3給出了新增不變量的列表。

表3 新增不變量列表

續(xù)表3
在過程藍圖中,所有的重構(gòu)操作都是基于過程藍圖樹結(jié)構(gòu)的變換操作,因此,基本樹變換操作是實現(xiàn)過程藍圖重構(gòu)的基礎(chǔ)。文獻[13,14]給出了20個基本的樹變換操作,我們在他們的基礎(chǔ)上進行了擴充,新增了10個基本樹變換操作。新增的基本樹變換操作如表4所示。

表4 新增基本樹變換操作列表
表4中S表示結(jié)構(gòu)操作,N表示結(jié)點操作。
文獻[13,14,16]在Martin Fowler提出70多種基于源碼的重構(gòu)操作的基礎(chǔ)上,先后一共定義了39種過程藍圖上的重構(gòu)規(guī)格說明,在他們的基礎(chǔ)上,基于過程藍圖重構(gòu)實現(xiàn)的需要,我們新增了10個重構(gòu)操作,如表5所示。

表5 新增重構(gòu)操作規(guī)格說明及分類

續(xù)表5
表5中RP為原子重構(gòu),R1為組合重構(gòu),R2為復雜重構(gòu);SR為結(jié)構(gòu)重構(gòu),NR為結(jié)點重構(gòu)。ACR為抽象概念層重構(gòu),ALR為抽象邏輯層重構(gòu),AIR為抽象實現(xiàn)層重構(gòu)。
過程藍圖的樹形結(jié)構(gòu)模型的定義以及重構(gòu)形式化工作的擴展,都是為過程藍圖上重構(gòu)操作的具體實現(xiàn)做理論準備,下面我們將基于幾種特定的應(yīng)用場景,給出對應(yīng)的重構(gòu)操作在過程藍圖上的實現(xiàn)。
3.2過程藍圖重構(gòu)操作實例
過程藍圖模型的構(gòu)建使用了我們的藍圖工具,中文化藍圖模型的建立需要定義中英文映射表mapping.zhb和tokens.sys英文變量符號表,使用過程這里不再詳述,可參見文獻[12],在執(zhí)行重構(gòu)之前須確保中文化的過程藍圖模型能正確生成重構(gòu)前的源代碼。以下實例同樣采用2.2節(jié)案例中提到的影片出租程序,展示了擴展后的重構(gòu)形式化定義在過程藍圖模型重構(gòu)操作中的具體應(yīng)用,并給出詳細的操作過程。
實例1:
重構(gòu)操作:提煉方法ExtractMethod(Class c, Method m, Tl t, Statement s, Method m1)
功能:針對類c的方法m(printInfo)的過程藍圖t,將t的語句塊s提煉為新的方法m1(printDetail)。
場景:Martin Fowler提出的22種代碼壞味道中,重復代碼、過長函數(shù)、過大的類、依戀情結(jié)、Switch語句等都是考慮執(zhí)行Extract Method的外在表現(xiàn),場景重前的源碼和構(gòu)造的過程藍圖模型如圖5所示。

圖5 重構(gòu)前ExtractMethod類的方法源碼和過程藍圖模型
執(zhí)行步驟:
(1) 運用已定義的導出分析函數(shù)LongMethodWithoutTempVar及其他原始分析函數(shù),分析重構(gòu)的前置條件和不變量是否滿足。
(2) 對“打印信息”過程藍圖模型進行基本樹變換操作。選定“打印橫幅”,執(zhí)行InsertElderBrother插入兄長“打印詳細信息”,并建立三層模型。跳轉(zhuǎn)步驟5。
(3) 在類上執(zhí)行CreateMethod添加新的方法“打印詳細信息”,接著執(zhí)行EditPBTree建立該方法的過程藍圖模型。然后連續(xù)使用CreateNode將“打印信息”藍圖模型中需要提煉的語句塊依次添加到“打印詳細信息”三層模型中。跳轉(zhuǎn)步驟5。
(4) 打開“打印信息”過程藍圖模型,執(zhí)行DeleteNode刪除已提煉到“打印詳細信息”藍圖模型中的所有節(jié)點。跳轉(zhuǎn)到步驟5。
(5) 執(zhí)行GenerateEnglishCode生成重構(gòu)后英文源碼,源碼有錯誤,返回步驟2-步驟4。直到最終源碼正確,重構(gòu)結(jié)束。
重構(gòu)結(jié)果:
重構(gòu)執(zhí)行后,從“打印信息”的語句塊中提煉出了一個新方法“打印詳細信息”,重構(gòu)后的兩個方法的過程藍圖模型和源碼如圖6所示。

圖6 重構(gòu)后Extract Method的的方法源碼和過程藍圖模型
實例2:
重構(gòu)操作:搬移函數(shù)MoveMethod(Class c1, Method m1, Class c2, Method m2)
功能:將類c1(Customer)中的方法m1(overRentCharge)搬移到類c2(CustomerType)中成為新的方法m2(overRentCharge)
場景:一個類中的方法有太多的行為與另外一個類相關(guān)而形成了高度耦合,就要考慮使用搬移函數(shù)MoveMethod,場景重構(gòu)前的類框架和方法rentCharge,overRentCharge的過程藍圖模型如圖7所示。

圖7 Move Method重構(gòu)之前的類框架和方法過程藍圖模型
執(zhí)行步驟:
(1) 運用已定義的導出分析函數(shù)MethodAppear及其他原始分析函數(shù),分析重構(gòu)的前置條件和不變量是否滿足。
(2) 在方法rentCharge和方法上overRentCharge上執(zhí)行一系列樹變換操作。先執(zhí)行CreateTree分別建立過程藍圖樹,然后執(zhí)行InsertChild、InsertElderBrother,每次建立一個結(jié)點,執(zhí)行UpdateNode進行更新保存。當所有的模型建立完畢之后執(zhí)行savePBModel保存當前的過程藍圖模型。跳轉(zhuǎn)到步驟5。
(3) 在類Customer中的方法overRentCharge上執(zhí)行copyMethod操作,然后在CustomerType類中執(zhí)行pasteMethod操作,這樣兩個類中都有方法overRentCharge。接著執(zhí)行MethodAppear查找overRentCharge出現(xiàn)的類,如果只有在Customer中調(diào)用了,可以直接對Customer中的overRentCharge執(zhí)行deleteMethod,刪除該方法,并更新rentCharge的過程藍圖模型為方法調(diào)用。如果還有其他類調(diào)用Customer中的overRentCharge方法,可以在過程藍圖中使用deleteAllChildren刪除overRentCharge的方法體,并執(zhí)行InsertChild添加新子節(jié)點,加入對_type. overRentCharge()的調(diào)用。跳轉(zhuǎn)到步驟5。
(4) 在類CustomerType的方法overRentCharge上執(zhí)行EditPBTree,編輯過程藍圖模型,修改結(jié)點的調(diào)用語句,并執(zhí)行UpdateNode更新結(jié)點和savePBModel保存模型,跳轉(zhuǎn)到步驟5。
(5) 執(zhí)行GenerateEnglishCode生成重構(gòu)后英文源碼,源碼有錯誤,返回步驟2-步驟4。直到最終源碼正確,重構(gòu)結(jié)束。
重構(gòu)結(jié)果:
重構(gòu)完成后,刪除了Customer類的overdraftCharge方法,在CustomerType類中添加了新的overdraftCharge方法,并進行了簡單的修改,重構(gòu)后的兩個類的兩個方法的過程藍圖模型和類框架如圖8所示。

圖8 Move Method重構(gòu)之后的類框架和方法過程藍圖模型
實例1和實例2的結(jié)果分別說明重構(gòu)形式化定義在簡單和復雜的過程藍圖模型重構(gòu)中是可以正確操作的,為以后重構(gòu)系統(tǒng)的實現(xiàn)奠定了形式化基礎(chǔ)。
程序模型重構(gòu)的實現(xiàn),需要建立UML模型、過程藍圖模型和程序源碼的一致性映射,程序源碼是基于文本的表示方法,UML模型和過程藍圖模型都是基于可視化圖形的表示方法,比起文本表示更直觀。源碼到UML模型的逆向映射可以借助于許多開源工具(如ArgoUML)自動變換,也可以手工添加;程序源碼到過程藍圖模型的轉(zhuǎn)換需要使用過程藍圖模型轉(zhuǎn)換工具自動轉(zhuǎn)換,然后加以修改。重構(gòu)完畢后UML模型可以正向生成框架代碼,過程藍圖模型可以直接生成完整的可執(zhí)行代碼。下面給出程序模型重構(gòu)實現(xiàn)的工作流程圖,如圖9所示。

圖9 程序模型重構(gòu)實現(xiàn)的工作流程圖
上述框架的實現(xiàn)主要包括以下幾步:
(1) 程序源碼到程序模型的逆向變換
程序模型包括UML模型和過程藍圖模型,源碼到模型的變換需要遵循特定的映射規(guī)則,首先,借助于開源的UML建模工具和過程藍圖變換系統(tǒng),實現(xiàn)半自動化的變換,生成初步的UML類圖模型和每個方法對應(yīng)的過程藍圖模型,然后人工在模型上進行修改,以保證變換后模型的正確性。
(2) UML類圖模型的重構(gòu)
UML類圖模型的重構(gòu)在類、方法、屬性三個層次上執(zhí)行。首先對UML類圖運用分析函數(shù)確保前置條件滿足,然后執(zhí)行類圖重構(gòu)操作,最后通過分析函數(shù)驗證后置條件和不變量是否滿足,是則結(jié)束,否則撤銷。
(3) 過程藍圖模型的重構(gòu)
過程藍圖的重構(gòu)執(zhí)行之前使用分析函數(shù)進行模型的分析,在滿足前置條件的前提下執(zhí)行重構(gòu)操作,使用不變量來進行行為保持驗證,運用樹變換操作來修改過程藍圖的三層模型,最后使用重構(gòu)變換系統(tǒng)執(zhí)行模型重構(gòu)變換,重構(gòu)變換系統(tǒng)需要分析函數(shù)、基本樹變換,重構(gòu)規(guī)格說明的支撐。使用重構(gòu)變換系統(tǒng)改變后的過程藍圖模型只有滿足后置條件和不變量才算是正確的重構(gòu)。
(4) 程序模型到程序源碼的正向變換
UML模型和過程藍圖模型執(zhí)行重構(gòu)操作之后,借助于UML建模工具和過程藍圖變換系統(tǒng),都可以正向生成程序源碼,從UML模型生成的是程序的框架代碼,有利于對程序的基本結(jié)構(gòu)進行把握。從過程藍圖模型生成可執(zhí)行的源碼,可以直接在開發(fā)平臺中進行調(diào)試驗證。
為了驗證程序模型重構(gòu)實現(xiàn)框架的可行性,UML類圖重構(gòu)操作的正確性,過程藍圖重構(gòu)形式化定義的正確性,過程藍圖模型重構(gòu)的優(yōu)越性,我們同樣采用2.2節(jié)案例中提到的影片出租程序進行實現(xiàn)。
5.1程序源碼重構(gòu)執(zhí)行過程
分解并重組Customer類的過長方法statement()
(1) 運用ExtractMethod()重構(gòu)將statement()中的switch代碼塊抽取成amountFor()方法,并在statement方法添加引用,thisAmount = amountFor(each)。
(2) amountFor()方法的某些變量名稱無意義,使用Rename()重構(gòu)將這些變量重命名,分析amountFor()方法時發(fā)現(xiàn),使用了來自Rental類的信息,沒有使用Customer類的信息,故需要運用MoveMethod()重構(gòu)將amountFor()方法搬移到Rental類中,再運用Rename()重構(gòu)將amountFor()重命名為getCharge(),最后更新statement()方法中對舊函數(shù)的所有引用,修改為:thisAmount = each.getCharge()。
(3) 這時我們發(fā)現(xiàn)臨時變量thisAmount多余了,運用ReplaceTempwithQuery()重構(gòu)將thisAmount去除,只需將thisAmount的引用全部替換成getCharge()。
(4) 使用類似(1)(2)(3)的方法,使用ExtractMethod重構(gòu)將“??头e分計算”代碼抽取為方法getFrequentRenterPoints(),然后替換引用為frequentRenterPoints += each.getFrequentRenterPoints()。
(5) 連續(xù)兩次交替使用ReplaceTempwithQuery和ExtractMethod和重構(gòu),在類Customer中提取出兩個方法getTotalCharge()和getTotalFrequentRenterPoints(),替換掉臨時變量totalAmount和frequentRenterPoints的引用,去除臨時變量。
5.2UML類圖模型重構(gòu)執(zhí)行過程
這里只給出重要屬性的UML類圖,并借此來說明UML類圖重構(gòu)實現(xiàn)的過程。
(1) 分析源程序,構(gòu)造UML類圖模型,重構(gòu)操作執(zhí)行之前UML類圖模型如圖10所示。

圖10 初始程序的UML類圖
(2) 重構(gòu)分解并重組Customer類的過長方法statement(),順序執(zhí)行UML類圖基本重構(gòu)操作ExtractMethod(),MoveMethod()和Rename(),得到如圖11所示的UML類圖。

圖11 抽取并移動getChange()方法后UML類圖
(3) 再次順序執(zhí)行和(2)中相同的3種UML類圖基本重構(gòu)操作,得到如圖12所示UML類圖。

圖12 抽取并移動getFrequentRenterPoints()方法后UML類圖
(4) 最后連續(xù)兩次順序交替使用UML類圖的基本重構(gòu)操作ExtractMethod()和ReplaceTempwithQuery(),最終得到如圖13所示的UML類圖。

圖13 重構(gòu)完成后的UML類圖
5.3過程藍圖模型重構(gòu)執(zhí)行過程
UML類圖模型重構(gòu)的直觀性框架為過程藍圖模型重構(gòu)在方法具體實現(xiàn)上提供了很好的指導。下面我們將以類圖模型重構(gòu)過程為基礎(chǔ),展示過程藍圖模型重構(gòu)在方法級別的實現(xiàn)過程。
(1) 使用過程藍圖工具自動化生成過程藍圖模型,并構(gòu)造中英文映射表和tokens,重構(gòu)之前的statement()方法的過程藍圖模型M的三層結(jié)構(gòu)分別如圖14-圖16所示。

圖14 重構(gòu)前statement()方法的抽象概念結(jié)構(gòu)圖-ACSD

圖15 重構(gòu)前statement()方法的抽象邏輯結(jié)構(gòu)圖-ALSD

圖16 重構(gòu)前statement()方法的抽象實現(xiàn)結(jié)構(gòu)圖-AISD
(2) 首先,在statemment()方法的過程藍圖模型M中對switch代碼段對應(yīng)的三層藍圖模型執(zhí)行ExtractMethod()重構(gòu),提取新的方法amountFor()的過程藍圖模型M1,接著使用MoveMethod()重構(gòu)將M1搬移到Rental類中,成為新的過程藍圖模型M2,然后使用Rename()重構(gòu)將M2描述的方法amountFor()重命名為getCharge(),更新M中的引用。其次,使用相同方法對M中“??头e分計算”對應(yīng)的三層藍圖模型執(zhí)行重構(gòu),最終在Rental類建立getFrequentRenterPoints()對應(yīng)的過程藍圖模型M3,并在M中更新對M3的引用。最后,在上面的基礎(chǔ)上,連續(xù)兩次順序交替使用過程藍圖重構(gòu)操作ReplaceTempwithQuery()和ExtractMethod(),在Customer類中建立兩個新的過程藍圖模型M4和M5,M4描述方法getTotalCharge(),M5描述方法getTotalFrequentRenterPoints()。重構(gòu)完成之后各個方法所對應(yīng)的過程藍圖模型分別如圖17-圖21所示。

圖17 重構(gòu)后Renter類的方法getFrequentRenterPoints()的過程藍圖模型

圖18 重構(gòu)后Customer類的方法statement()的過程藍圖模型

圖19 重構(gòu)后Customer類方法getTotalFrequentRenterPoints()過程藍圖模型

圖20 重構(gòu)后Customer類的方法getTotalCharge()的過程藍圖模型

圖21 重構(gòu)后Renter類的方法getCharge()的過程藍圖模型
通過比較可以看出源碼重構(gòu)的可讀性差,難以找到需要重構(gòu)的地方,而且容易出錯;UML類圖重構(gòu)直觀性好,效率高,但只能進行類模型框架重構(gòu);而過程藍圖重構(gòu)彌補了UML模型不能執(zhí)行過程級別重構(gòu)的缺點,并且藍圖模型與源碼一一對應(yīng)使得程序更易于理解,提高了重構(gòu)的效率和程序的可讀性。
本文研究了重構(gòu)操作在程序模型級別上的執(zhí)行實例,使用UML類圖執(zhí)行程序框架級別的重構(gòu)變換,運用過程藍圖模型描述類的方法實現(xiàn),執(zhí)行方法級別的重構(gòu)變換。
本文的貢獻主要包括:
? 在屬性、方法、類三個層次上定義了新的類圖基本重構(gòu)操作。
? 給出三種代表性類圖模型基本和組合重構(gòu)操作實例。
? 完善過程藍圖模型重構(gòu)的形式化定義,新增分析函數(shù)、不變量、基本樹變換操作、重構(gòu)規(guī)格說明定義。
? 給出兩種代表性的簡單和復雜過程藍圖模型重構(gòu)操作實例。
? 給出一種程序藍圖模型重構(gòu)的實現(xiàn)框架。
? 進行了源碼重構(gòu)、UML類圖重構(gòu),過程藍圖模型重構(gòu)實驗驗證與比較。
程序藍圖重構(gòu)實現(xiàn)框架有待于進一步在大型的軟件系統(tǒng)中進行驗證,今后的工作中我們將進一步完善過程藍圖工具對模型重構(gòu)變換的支持,最終給出一套具有較高價值的模型重構(gòu)方法和工具。
[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 自動化重構(gòu)工具的研究[J]. 計算機與信息技術(shù),2005(5):32-37.
[12] 劉建賓.過程藍圖設(shè)計方法學[M].北京:科學出版社,2005.
[13] 楊林邦. 基于過程藍圖的重構(gòu)研究[D]. 汕頭大學,2006.
[14] 易長安. 基于類圖和過程藍圖的模型重構(gòu)操作的研究[D]. 汕頭大學,2007.
[15] 梅新云. 程序模型重構(gòu)實現(xiàn)方法與工具[D]. 北京信息科技大學,2011.
[16] 王俊飛. 程序模型再工程方法及其支撐工具研究[D]. 北京信息科技大學,2012.
[17] 胡偉奇. JAVA藍圖模式及其重構(gòu)方法研究[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。
北京市教委人才培養(yǎng)模式創(chuàng)新實驗區(qū)項目(京教函[2009]630號);北京市教委科技計劃面上項目(KM201311232013)。
梁朋舉,碩士生,主研領(lǐng)域:模型驅(qū)動架構(gòu),過程藍圖。劉建賓,教授。鄭麗偉,講師。
TP311
A
10.3969/j.issn.1000-386x.2016.03.005