梁朋舉 劉建賓 鄭麗偉
(北京信息科技大學計算機學院 北京 100101)
?
程序藍圖模型重構操作實例研究
梁朋舉劉建賓鄭麗偉
(北京信息科技大學計算機學院北京 100101)
重構可以改善軟件系統的內部結構,提高軟件可理解性、可維護性,而又不改變軟件的外部行為。傳統的源碼層次的重構雖有很多重構工具的支持,但是對于復雜軟件的重構難度大,容易出錯。針對這種情況,提出基于程序藍圖模型層次的重構??紤]到UML模型直觀性的特點,給出UML類圖模型在系統體系結構上的重構操作和實例,為重構在軟件框架結構上的實施提供有力的支持。深入研究過程藍圖模型使用樹形結構來描述程序的方法,定義過程藍圖相關重構操作并給出具體操作實例及過程,最后從過程藍圖模型生成新的源碼。實驗結果表明,UML模型和過程藍圖模型層次上的重構,提高了重構的抽象級別和效率。該方法能有效支持復雜軟件的重構,并減少出錯率。
重構UML模型過程藍圖模型程序模型
當軟件所處的環境發生變化或者需求改變時,軟件需要不斷地增強、修改以適應新的變化,在這個發展的過程中,程序代碼會變得越來越復雜,并且可能會偏離最初的設計意圖,因而導致軟件的質量持續降低。正是由于這個原因,軟件開發的大量成本都花費在軟件的維護上。隨著軟件系統的演變,系統的結構越來越復雜,性能越來越差,為解決這一問題,重構技術開始產生并得到發展。“重構”一詞最早是由Opdyke[1]提出,他把重構定義為“面向對象領域的行為保持的重建的變體”。重構沒有統一的定義,一個被廣泛認可的定義是Martin Fowler[2]給出的定義,他把重構定義為動詞和名詞兩種形式?!爸貥?名詞):對軟件內部結構的一種調整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。重構(動詞):使用一系列重構的手法,在不改變軟件可觀察行為的前提下,調整其結構?!?/p>
目前的重構技術的對象主要集中在程序源碼上,屬于代碼級別重構,重構之前需要先對源碼分析,進行重構定位,然后才能執行重構。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類圖上的重構分為基本重構和組合重構?;局貥嬍沁M行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]中的影片出租程序,并在其基礎上進行適當擴展。顧客可以通過該系統租用不同的影片,系統可根據影片租用時間和影片類型計算費用并打印詳單,亦可為??陀嬎惴e分。
實例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中“??头e分計算”對應的三層藍圖模型執行重構,最終在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