介紹 重構在現代軟件開發過程中扮演著重要的角色
它能夠減輕軟件開發人員的工作負擔
提高軟件開發的生產效率
為了闡明重構的重要性
我們在這裡引用了developerWorks上David Carew提供的關於重構的教程中的一段話
現在
一個開發者的工作大部分在於對現有的代碼進行修改
而不是起草寫新的代碼
簡單的修改可能包括對現有代碼進行添加
然而
多樣化的修改或擴展的改變會使軟件內部結構開始惡化
重構改變軟件的內部結構使得軟件更容易理解並且在不需要改變其顯著的行為的情況下使得修改的代價也更小
在Java軟件開發過程中
通過使用Eclipse提供的重構工具
我們至少獲得了以下好處
最終產品更為健壯
我們對程序代碼的修改將不太可能出錯
出現遺漏修改的可能變少
即使出現問題也能夠通過Undo功能回退到重構前的狀態
提高了生產效率
通常一次重構能夠完成對程序代碼的多處改動
最為明顯的例子可能是Eclipse提供的Rename重構
它能夠在修改名稱的同時相應的更改所有的引用
Eclipse為我們提供了多種實用的重構功能
在軟件開發過程中使用這些重構能夠給我們帶來極大的好處
然而
針對每個開發人員的特殊需要
總有一些迫切需要的功能是不能通過已有的重構來獲得的
這個時候
我們可以對Eclipse平台進行一些擴展
創建適應我們自己需要的重構
如果這個重構恰好能夠符合大多數人的需要
我們也可以像其他Eclipse的contributor一樣
將我們的重構貢獻給Eclipse社區
接下來
我們將通過一個例子來展示如何在Eclipse中創建新的重構功能
我們這裡創建的重構將用於遷移JUnit的測試用例
我們知道
在當前版本的JUnit中
一個用於測試的函數必須以字符串
test
作為方法名稱的開始
而在即將來到的JUnit
中
一個
@Test
的Annotation被用於標明方法是一個測試方法
我們將要創建的重構將完成這個遷移工作
即在所有的以
test
開始的方法之前加上
@Test
標記
@Test Annotation還可以包含一個timeout屬性用來規定方法的最大執行時間
我們在向導中提供了一個頁面供用戶選擇是否需要timeout屬性
結果預覽 為了給讀者一個直觀的感受
我們下面首先介紹本文中例子的實際運行效果
在閱讀完本文之後
讀者朋友也能夠順利的完成類似的功能
啟動例子程序提供的Refactor之後
我們獲得了一個由三個頁面組成的向導
在第一個頁面中
用戶可以選擇是否需要timeout參數
並且用戶能夠設置timeout參數的值
圖 輸入參數
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013112320425072.gif)
當用戶輸入參數完畢之後
通過單擊Next按鈕我們將進入下一個頁面
向導將進行初始條件檢查和最終條件檢查
並將檢查的結果反饋給用戶
在圖
中我們可以看到
初始條件和最終條件都正常
因此我們可以進入下一步
圖 顯示條件檢查
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013112320425007.gif)
接下來是預覽窗口(圖
)
向導用直觀的界面顯示了在應用向導之後
我們將會對源代碼造成怎樣的改動
用戶可以在這個頁面中判斷最終的修改是否符合自己的需要
另外
用戶也能夠選擇性的取消對某些文件的修改
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013112320425042.gif)
當用戶檢查預覽頁面確認沒有問題之後
用戶可以按下Finish按鈕從而完成重構
這個時候
源代碼會發生修改
最後的結果如下所示
清單
package main;
public class TestSomething {
@Test(timeout=
)
public void testSomething(){
}
}
總體結構和流程 在Eclipse中
一個重構操作主要由以下三個部分組成
RefactoringWizard類
RefactoringWizard提供了向導式的用戶界面來引導用戶完成重構工作
不需要我們做任何工作
Eclipse已經通過RefactoringWizard為我們提供了預覽頁面
條件檢查頁面以及Undo/Redo等功能
我們需要繼承這個類從而為重構過程提供特定的用戶界面
Refactoring類
Refactoring類完成具體的定位和修改代碼功能
為了建立新的Refactoring
我們需要繼承這個類並實現重構的邏輯部分
AST和ASTParser
在Refactoring類中
我們需要對代碼進行定位和修改
這可以通過AST機制來完成
AST是abstract syntax tree的簡稱
它能夠將Java代碼解析成為一個樹形結構
在利用了AST樹之後
對源代碼的修改變成了對AST樹的遍歷
更改節點屬性
以及插入和刪除節點等
一個典型的重構操作流程如下所示
用戶選擇要進行重構的對象
通過菜單項或按鈕啟動重構操作
創建具體的Refactoring類
彈出RefactoringWizard
RefactoringWizard與用戶交互
引導用戶輸入必要的參數
RefactoringWizard調用Refactoring類的函數進行條件檢查
Refactoring類創建AST
並利用其對源代碼進行定位和修改
這裡進行的修改並不直接應用到源代碼上
而是被保存成Change對象
供Refactoring框架使用
RefactoringWizard調用Refactoring類的函數
獲得重構內容的詳細描述信息(即第
步生成的Change對象)
顯示在預覽界面上
待用戶確認
用戶確認後Refactoring框架將修改代碼
重構操作結束
接下來
我們將詳細介紹新建重構類型的各個步驟
創建插件工程 在大家對整個系統構架有了一個大概的了解之後
我們的介紹就從創建工程開始
大家都知道Eclipse提供了很好的擴展性
通過創建插件就能把我們要添加的重構功能無縫的插入到Eclipse平台中
創建插件工程的方法在很多地方都有介紹
這裡不再詳細講解
如果需要基礎的插件開發知識
我們可以參考《 開發 Eclipse 插件》
樹立基本的插件開發意識
通過菜單 File
> New
> Project
選擇Plug
in Project
點擊Next
出現對話框
輸入項目名稱manage
annotation
接受其他選項的默認值
點擊Next
出現插件屬性設置的對話框
繼續接受默認值
點擊Next
出現選擇插件模板對話框
該工程要在Refactor菜單中添加一個新的菜單項
所以這裡我們采用
Hello
World
的插件模板
點擊Next
修改
Action類名稱
的值為AnnotationManageAction
點擊Finish按鈕
至此
一個最基本Eclipse工作台的插件工程就被創建出來了
插件工程創建後
缺省進入Plug
in開發透視圖
Plug
in Manifest編輯器自動打開
顯示這個插件工程的基本信息
如對其他插件的依賴
擴展點
構建(build)的配置信息等等
由於該工程需要用到其他插件的功能
必須為其添加到其他插件的依賴
在Plug
in Manifest編輯器點擊Dependencies頁面
在該頁面中的Required Plug
ins列表中通過Add按鈕添加如下的插件
清單
org
eclipse
jface
text
re
refactoring
org
eclipse
ltk
ui
refactoring
org
eclipse
jdt
re
或者也可以通過直接修改MANIFEST
MF文件完成
操作完成後察看MANIFEST
MF文件
注意Require
Bundle列表中是否出現了新添加的這幾項
MANIFEST
MF文件如下
清單
Manifest
Version:
Bundle
ManifestVersion:
Bundle
Name: Annotation Plug
in
Bundle
SymbolicName: manage
annotation; singleton:=true
Bundle
Version:
Bundle
Activator: manage
annotation
AnnotationPlugin
Bundle
Localization: plugin
Require
Bundle: org
eclipse
ui
re
runtime
org
eclipse
jface
text
re
refactoring
org
eclipse
ltk
ui
refactoring
org
eclipse
jdt
re
Eclipse
AutoStart: true
在Plug
in Manifest編輯器中打開插件清單文件plugin
xml
可以看到
這個插件擴展了org
eclipse
ui
actionSets擴展點
這是一個基本的Eclipse工作台的擴展點
通過擴展它
插件可以很簡單得對Eclipse的菜單
工具條進行擴展
這個plugin
xml是
Hello
World
插件模板的清單文件
我們把它改成適合這個工程的文件
清單如下
清單
<?xml version=
encoding=
UTF
?>
<?eclipse version=
?>
<plugin>
<extension
point=
org
eclipse
ui
actionSets
>
<actionSet
label=
Annotation Action Set
visible=
true
id=
manage
annotation
actionSet
>
<menu
label=
%nu
label
path=
source
id=
org
eclipse
jdnu
>
<separator name=
reorgGroup
/>
</menu>
<action
class=
manage
annotation
actions
AnnotationManageAction
icon=
icons/sample
gif
id=
manage
annotation
actions
AnnotationManageAction
label=
%Annotation
manage
menubarPath=
org
eclipse
jdnu/reorgGroup
toolbarPath=
reorgGroup
tooltip=
Manage Annotation in Java Project
/>
</actionSet>
</extension>
</plugin>
該清單文件表明
在Refactor菜單中添加了一個新菜單項
Annotation Manage
並在工具條上相應添加了一個按鈕
點擊菜單項或者按鈕的事件由類
manage
annotation
actions
AnnotationManageAction
處理
最後需要修改的就是manage
annotation
actions
AnnotationManageAction類
它繼承了org
eclipse
ui
IWorkbenchWindowActionDelegate接口
該接口用於處理各種通過擴展點添加的操作
當菜單項或者按鈕被點擊時
這個類就被Eclipse工作台裝載進來
處理轉發過來的請求以及接下來的操作
AnnotationManageAction被創建後
一旦用戶的選擇部分有所改變
接口的selectionChanged函數就會被觸發
告知用戶所選擇的部分
可以在這個函數中根據用戶的選擇相應的修改操作的可用性或者其他顯示屬性
例如在本文的工程中
我們希望只有當用戶選擇了一個Java模型元素時才能使用這個操作
那麼就需要在selectionChanged中添加如下的代碼
清單
public void selectionChanged(IAction action
ISelection selection) {
if (selection
isEmpty())
select = null;
else if (selection instanceof IStructuredSelection) {
IStructuredSelection strut = ((IStructuredSelection) selection);
if (strut
size() !=
)
select = null;
if (strut
getFirstElement() instanceof IJavaElement)
select = (IJavaElement) strut
getFirstElement();
} else
select = null;
action
setEnabled(select != null);
}
selectionChanged函數的參數selection記錄了用戶選擇的部分
我們首先判斷它的選擇部分的數目是否為一
然後判斷這個唯一的選擇部分是否為Java模型元素
這兩個條件任何一個不滿足都會導致action
setEnabled(false)的執行
這時會彈出如下的對話框說明操作不可用
同時菜單項和按鈕都會顯示成灰色
直到用戶選擇了合適的部分時
菜單項和按鈕才會實顯
就可以進行具體的操作了
圖 表明Action目前不能執行的對話框
educitycn/img_///jpg > 操作的執行是在AnnotationManageAction的run函數中實現的
例如在本文的工程中
就是彈出RefactoringWizard對話框
指導用戶完成重構的工作
這些我們將在下面的章節中講述
擴展Refactoring類 通過前面系統構架的介紹
大家知道了Refactoring和RefactoringWizard是完成EClipse重構功能的基礎類
在創建好插件工程後
我們就通過擴展Refactoring來實現具體的功能
Refactoring是所有支持代碼轉化的類的抽象父類
它在整個流程中與RefactoringWizard交互以完成重構的功能
起著非常重要的作用
這些類需要提供以下兩類方法
用於條件檢查的方法
判斷重構操作大體而言能否執行
以及具體的轉化能否完成
創建Change對象的方法
Change對象描述了所有將要執行的對當前代碼的修改操作
Refactoring類的典型流程如下所示
具體的Refactoring類被創建
獲得用戶選擇的要進行重構的對象
初始化該Refactoring類
這個由具體的實現類給出相應的方法
在重構操作開始執行時
首先調用Refactoring的checkInitialConditions(IProgressMonitor) 基於用戶選擇的對象做一個的初始檢查
這個通常由界面自動執行
返回RefactoringStatus
FATAL表明初始檢查沒有通過
重構操作不能繼續
獲得進行重構的其他參數
比如
對重命名操作來說就是指新名字
這個通常是由界面根據用戶的輸入提供的
由具體的實現類給出相應的方法
獲得用戶輸入參數後
調用Refactoring的checkFinalConditions(IProgressMonitor)進行剩下的檢查
這個通常由界面自動執行
返回RefactoringStatus
FATAL表明最後的檢查沒有通過
重構操作不能繼續
調用Refactoring的createChange(IProgressMonitor)獲得Change對象
這個通常由界面自動執行
界面可以根據Change對象顯示預覽界面
基於以上的介紹
為了實現本文工程中的重構操作
我們需要擴展Refactoring類
為它增加一個構造函數
並且具體實現checkInitialConditions
checkFinalConditions和createChange三個函數
首先通過菜單File
> New
>Class彈出創建類的對話框
輸入包名manage
annotation
refactor
類名AnnotationRefactoring
輸入父類re
refactoring
Refactoring
選中
繼承抽象方法
復選框
點擊完成按鈕
一個擴展了Refactoring的最基本的類AnnotationRefactoring就被創建出來了
首先為其增加構造函數
以用戶選擇的Java模型元素作為參數
Refactoring分析這個參數以得到所有相關的可寫Java文件
作為重構操作的對象
如果該模型元素包含在Java文件中
則找到包含它的文件節點
如果該模型元素包含Java文件
則找到它的所有子Java文件
構造函數代碼如下
清單
public AnnotationRefactoring(IJavaElement element) {
while (element
getElementType() > IJavaElement
COMPILATION_UNIT) {
element = element
getParent();
if (element == null)
return;
}
if (element
getElementType() == IJavaElement
COMPILATION_UNIT) {
if (!element
isReadOnly())
compilationUnits
add(element);
}
if (element
getElementType() < IJavaElement
COMPILATION_UNIT)
findWritableCompilationUnits(element);
}
接著完成checkInitialConditions函數
實現初始檢查的具體操作
作為示例
在本文工程中我們不進行任何具體的檢查操作
只簡單得給出初始檢查成功的信息
返回RefactoringStatus
INFO以使重構操作繼續執行
checkInitialConditions函數代碼如下
清單
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
throws CoreException
OperationCanceledException {
return RefactoringStatus
createInfoStatus(
Initial Condition is OK!
);
}
接著完成checkFinalConditions函數
實現獲得用戶輸入參數後的後續檢查操作
在本文工程中
我們首先收集所有需要添加注釋的以test開頭的方法
判斷是否不存在這樣的方法
如果不存在給出出錯信息
返回RefactoringStatus
FATAL以結束重構操作
如果存在這樣的方法
則給出後續檢查成功的信息
返回RefactoringStatus
INFO
checkFinalConditions函數代碼如下
清單
public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
throws CoreException
OperationCanceledException {
collectChanges();
if (fChangeManager
size() ==
)
return RefactoringStatus
createFatalErrorStatus(
No testing methods found!
);
else return RefactoringStatus
createInfoStatus(
Final condition is OK!
);
}
最後
創建Change對象的createChange函數是整個重構操作中最核心的代碼
它的實現將在下面章節中介紹
使用AST構造Change對象 當我們找到了修改的位置時
我們有兩個選擇
通過IScanner接口掃描代碼
然後通過IBuffer接口直接修改代碼
通過遍歷和編輯AST樹進行結構化的修改
DeveloperWorks提供的文章《擴展Eclipse的Java開發工具》中
給出了使用IBuffer接口的例子
現在我們要講述使用AST來遍歷和修改Java源代碼的方法
AST是abstract syntax tree的縮寫
它是Eclipse中的Java開發環境(JDT)為我們提供的極為強大的源代碼解析和編輯工具
在使用AST樹提供的功能之前
我們首先要創建AST樹
由於AST樹的構建是一項費時的操作
JDT缺省情況下不將源代碼解析為AST樹
下面的代碼演示了獲得一個ICompilationUnit對應的AST樹的過程
在JDT提供的API中
ICompilationUnit接口用於表示一個可以被編譯的源代碼文件
在我們提供的例子程序中
我們通過下面的代碼將整個文件解析成為了一顆AST樹
清單
ASTParser parser = ASTParser
newParser(AST
JLS
);
parser
setSource(cu);
ASTNode root = parser
createAST(null);
AST樹中的每個節點都是ASTNode類型
通過Visit模式
我們可以訪問一個ASTNode包含的所有節點
下面的代碼演示了訪問一個AST節點並獲得其中所有的MethodDeclaration節點的方法
清單
private void getMethods(ASTNode cuu
final List methods) {
cuu
accept(new ASTVisitor() {
public boolean visit(MethodDeclaration node) {
methods
add(node);
return false;
}
});
}
在收集到了所有的MethodDeclaration節點之後
我們就可以通過向AST樹中插入和刪除節點或者修改已有的節點的方法來修改AST樹了
下面的代碼演示了使用AST工具為方法添加@Test Annotation的功能
清單
private boolean collectChanges(CompilationUnit root
MethodDeclaration method) {
if (method
getName()
getFullyQualifiedName()
startsWith(
test
)) {
AST ast = method
getAST();
if (needTimeout) {
NormalAnnotation na = ast
newNormalAnnotation();
na
setTypeName(ast
newSimpleName(
Test
));
MemberValuePair pair = ast
newMemberValuePair();
pair
setName(ast
newSimpleName(
timeout
));
pair
setValue(ast
newNumberLiteral(
));
na
values()
add(pair);
method
modifiers()
add(
na);
} else {
MarkerAnnotation na = ast
newMarkerAnnotation();
na
setTypeName(ast
newSimpleName(
Test
));
method
modifiers()
add(
na);
}
return true;
}
return false;
}
在Refactoring框架中
我們要求對AST樹的修改並不立刻反映到源代碼中
相反
我們需要一個能記錄整個修改過程的Change對象
Refactoring框架將利用這個Change對象來顯示Priveiw窗口
進行Undo和Redo等操作
大致上
我們記錄對一個AST樹的修改從而生成Change對象的過程如以下代碼所示
清單
root
recordModifications();
//在這裡修改AST樹…
TextEdit edits = root
rewrite(document
cu
getJavaProject()
getOptions(true));
TextFileChange change = new TextFileChange(
(IFile) cu
getResource());
change
setEdit(edits);
最後
由於Refactoring類的createChange方法僅返回一個Change對象
如果我們需要對多個源代碼文件進行修改
我們可以利用CompositeChange類將多個Change對象封裝成一個Change對象
這個過程可能類似如下代碼所執行的流程
清單
public Change createChange(IProgressMonitor pm) throws CoreException
OperationCanceledException {
Change[] changes = new Change[fChangeManager
size()];
System
arraycopy(fChangeManager
toArray()
changes
fChangeManager
size());
CompositeChange change = new CompositeChange(
Add @Override Annotation
changes);
return change;
}
擴展RefactoringWizard 框架 Eclipse中的RefactoringWizard框架擴展了Eclipse的Wizard框架
關於Wizard框架的介紹可以在Eclipse的幫助系統中找到
這裡我們僅從OO設計和架構的角度探討一下RefactoringWizard框架
我們從Wizard相關的幾個類開始
WizardPage類
WizardPage是一個包含了多個界面元素(比如文本框Text
按鈕Button)的一個界面組合部分
各個Page之間是獨立的
是可以動態加載的
WizardPage類的職責有
組合SWT界面元素
構造出一個界面頁
定義本身界面元素的操作行為
在RefactoringWizard框架中預設了兩個通用的屬性頁
PreviewWizardPage和ErrorWizardPage
PreviewWizardPage類是用來預覽重構後的修改
對比代碼或其他資源的變化
ErrorWizardPage類是用來處理條件檢查及錯誤狀態通知的
我們只需擴展RefactoringWizard框架就可以自動獲取這兩項強大的功能
Wizard類
一個Wizard就是一個裝載一系列WizardPage頁的容器
Wizard類的職責有
裝載一系列WizardPage
構造出一個復雜的界面
裝載領域類來處理具體業務邏輯
(在RefactoringWizard框架中這個類就是Refactoring類)
維護WizardPage頁之間以及頁與領域類之間的數據傳遞和狀態共享
(在這裡要補充一點
其實在具體RefactoringWizard框架的實現中有專門的類來分擔這部分職責
)
我們的界面行為可以千變萬化(通過組合不同的WizardPage)
而負責處理業務邏輯的領域類也可以獨立的變化
你可以隨意擴展Wizard的界面功能(-對擴展開放)
而不用修改現有RefactoringWizard框架(-對修改封閉)
這正是OO設計的最基本原則-OCP(Open
Close Principle)
WizardDialog類
這個對話框類的主要職責是構造一個完整的GUI界面以及操作界面
它預設了一些按鈕(Back
Next
Finish
Cancel)等界面元素
它負責裝載Wizard類
操作時通過按鈕Back
Next來在多個WizardPage之間切換
下面我們給出RefactoringWizard框架的架構圖
圖 Refactoring Wizard架構圖
educitycn/img_///gif > 從圖
中我們可以看到
如果我們把每一個WizardPage頁看作一項業務
那麼Refactoring正是處理業務邏輯的控制中心
它封裝了所有對業務邏輯的處理
當然它可以在將處理任務委任出去
但請注意
它並不負責實現業務流程
也就是說各業務(各個Page界面)之間的邏輯順序關系不由它維護
RefactoringWizard框架充分考慮到了應用的可擴展性
它在SWT的MVC(模型-視圖-控制)元架構模式的基礎上
添加了一些新的架構元素
MVC模式促使業務邏輯與界面分離
界面與控制行為分離
而RefactoringWizard框架增強了界面本身分離的特性
它將一個完整的界面分拆成多個頁面
用戶可以動態組合這些頁面或添加新的頁面來擴展界面行為
這種特性-界面的動態組合
低耦合
高內聚
封裝良好的接口-讓我們領略到了OO設計的精髓
下面我們通過以下幾個步驟來擴展RefactoringWizard框架
擴展RefactoringWizardPage
擴展RefactoringWizard
啟動RefactoringWizard
第一步
擴展RefactoringWizardPage
首先我們新建一個類AnnotationRefactoringWizardPage
它需要繼承UserInputWizardPage類(其父類是RefactoringWizardPage
而RefactoringWizardPage最終實現了IDialogPage接口)
接下來就是實現IDialogPage接口的createControl(…)方法
在這個方法裡實現你的界面行為
比如我們例子中的TimeOut文本框
代碼清單如下
清單
/**
* create composite to add UI elements
*/
public void createControl(Composite parent) {
// define UI
Composite composite = new Composite(parent
SWT
NONE);
GridLayout lay = new GridLayout();
lay
numColumns =
;
composite
setLayout(lay);
btnCheck = new Button(composite
SWT
CHECK);
btnCheck
setText(
Add timeout parameter
);
GridData gdBtnCheck = new GridData();
gdBtnCheck
horizontalSpan =
;
gdBtnCheck
horizontalAlignment = GridData
FILL;
btnCheck
setLayoutData(gdBtnCheck);
labName = new Label(composite
SWT
WRAP);
labName
setText(
TimeOut:
);
GridData gdLabName = new GridData();
gdLabName
horizontalAlignment = GridData
BEGINNING;
gdLabName
grabExcessHorizontalSpace = true;
labName
setLayoutData(gdLabName);
txtTimeOut = new Text(composite
SWT
SINGLE | SWT
BORDER);
GridData gdTxtTimeOut = new GridData();
gdTxtTimeOut
horizontalAlignment = GridData
END;
gdLabName
grabExcessHorizontalSpace = true;
txtTimeOut
setLayoutData(gdTxtTimeOut);
txtTimeOut
setText(
);
// init status
labName
setEnabled(false);
txtTimeOut
setEnabled(false);
// add listener
defineListener();
// 將composite納入框架的控制
setControl(composite);
Dialog
applyDialogFont(composite);
}
在這裡我們要特別注意的一點是在定義完我們的界面元素後
需要將自定義的Composite納入框架的控制
就是這行代碼
setControl(composite);
在我們處理完輸入數據檢查後進入下一頁面之前
我們需要設置頁面完成的狀態
以及傳遞輸入數據到領域類Refactoring
我們用以下代碼設置好頁面完成的狀態後
下個頁面ErrorWizardPage就會處理顯示邏輯
清單
private void notifyStatus(boolean valid
String message) {
//設置錯誤信息
setErrorMessage(message);
//設置頁面完成狀態
setPageComplete(valid);
}
傳遞輸入數據通過以下代碼來處理
清單
private void setRefactoring(boolean selection
String text) {
AnnotationRefactoring refactoring = (AnnotationRefactoring) getRefactoring();
refactoring
setNeedTimeout(true);
if(selection) {
refactoring
setTimeout(Integer
valueOf(txtTimeOut
getText())
intValue());
}
}
其中getRefactoring()方法是繼承自RefactoringWizardPage的方法
由於我們的RefactoringWizard類裝載了RefactoringWizardPage和Refactoring類
這個方法是從RefactoringWizard類中獲得的
這裡面用到了Observer設計模式
至此
我們完成RefactoringWizardPage的擴展
第二步
擴展RefactoringWizard
首先我們新建一個類AnnotationRefactoringWizard
它需要繼承RefactoringWizard類
這個類中我們只需要加載定義好的AnnotationRefactoringWizardPage類和AnnotationRefactoring類
當然復雜的處理已經有RefactoringWizard框架處理好了
下面我們在構造函數中加載Refactoring類
清單
public AnnotationRefactoringWizard(Refactoring refactoring) {
super(refactoring
WIZARD_BASED_USER_INTERFACE);
}
然後我們加載我們的AnnotationRefactoringWizardPage類
只需重載父類RefactoringWizard的addUserInputPages()方法就可以
清單
protected void addUserInputPages() {
page = new AnnotationRefactoringWizardPage(
refactor annotation
);
addPage(page);
}
第三步
啟動RefactoringWizard
擴展好RefactoringWizard之後
就需要在用戶點擊菜單項或是按鈕時彈出這個對話框
RefactoringWizard最好使用RefactoringWizardOpenOperation類來打開(當然也可以用RefactoringWizardDialog)
RefactoringWizardOpenOperation首先進行重構的初始檢查
通過後才打開RefactoringWinzard對話框
否則就會打開錯誤對話框
前面完成創建插件工程時我們提到
彈出RefactoringWizard對話框的代碼應該放到響應菜單操作的類的run函數中
具體到本文工程中
就是把下面的代碼放到AnnotationManageAction的run函數中
這些代碼首先依次構造Refactoring和RefacoringWizard子類AnnotationRefactoring和AnnotationRefactoringWizard
並將AnnotationRefactoring的引用傳遞給AnnotationRefactoringWizard
然後用RefactoringWizardOpenOperation打開AnnotationRefactoringWizard
彈出向導對話框
清單
public void run(IAction action) {
Shell shell = window
getShell();
AnnotationRefactoring refactor = new AnnotationRefactoring(select);
AnnotationRefactoringWizard wizard = new AnnotationRefactoringWizard(
refactor);
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(
wizard);
try {
op
run(shell
Inserting @Override Annotation
);
} catch (InterruptedException e) {
e
printStackTrace();
}
}
小結 在Eclipse中有效的利用重構能夠大大的減輕軟件開發人員的工作負擔
提高軟件的健壯性
然而
目前重構仍然處在一個工具缺乏的時代
以Eclipse為例
只有JDT提供的重構工具最為完善
而針對其他語言例如C++
Python等的開發環境
都缺乏對應的重構功能
通過本文提供的方法
我們能夠有效的利用Eclipse中的重構框架創建新的重構
從而進一步提高已有開發環境的效率
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28943.html