熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Eclipse中自動重構實現探索

2022-06-13   來源: Java開源技術 

  本文用eclipse的自動重構功能對一個程序實例進行重構目的是探索Eclipse自動重構可以在多大程度上輔助重構這個過程程序實例使用《RefactoringImproving the Design of Existing Code》一書中的例子
  
  Eclipse的自動重構功能能夠很好地支持各種程序元素的重命名並自動更新相關的引用Eclipse能夠支持方法字段在類之間移動並自動更新引用Eclipse較好地支持內聯字段函數的更新替換Eclipse較好地支持抽取方法變量等程序元素
  
  重構的過程是一個不斷嘗試和探索的過程Eclipse的重構支持撤銷和重做並且能夠預覽重構結果這些是很實用的功能
  
  Eclipse的重命名抽取方法移動內聯功能更改方法特征符等代碼結構級別的重構方法是比較成熟同時也值得使用的功能至於設計結構上的重構eclipse還不能很好地支持但是作者相信自動重構的理念應該是工具輔助下的重構工作人仍然承擔大部分重構工作
  
  預備工作
  
  本文使用《RefactoringImproving the Design of Existing Code》一書第一章的例子重構前的代碼及每一步重構後的代碼見附件讀者最好配合《RefactoringImproving the Design of Existing Code》一書閱讀本文
  
  Eclipse使用如下版本
   
  同時安裝了中文語言包
  
  重構第一步分解並重組statement()
  
  目的
  
   把statement()函數中的swich語句提煉到獨立的函數amountFor()中
  
   修改amountFor()參數命名
  
  重構方法
  
  Extract Method
  Rename Method
  
  方法
  
  選中swich語句的代碼塊在右鍵菜單中選擇重構/抽取方法出現參數對話框Eclipse自動分析代碼塊中的局部變量找到了兩個局部變量each和thisAmount其中each只是在代碼塊中被讀取但thisAmount會在代碼塊中被修改按照重構Extract Method總結出來的規則應該把each當作抽取函數的參數thisAmount當作抽取函數的返回值然而Eclipse並不做區分直接把這兩個變量當作抽取新方法的參數如圖
   
  我們的目的是把在抽取函數中不會被修改的each作為參數會被修改的thisAmount作為返回值解決的辦法是把 double thisAmount = ; 這行代碼移到switch語句的上面變成這樣
  
  double thisAmount = ;
  switch(eachgetMovie()getPriceCode()){
  case MovieREGULAR:
  thisAmount += ;
  if(eachgetDaysRented()>)
  thisAmount += (eachgetDaysRented())*;
  break;
  
  case MovieNEW_RELEASE:
  thisAmount += eachgetDaysRented()*;
  break;
  
  case MovieCHILDRENS:
  thisAmount += ;
  if(eachgetDaysRented()>)
  thisAmount += (eachgetDaysRented())*;
  break;
  }
  
  選中這段代碼在右鍵菜單中選擇重構/抽取方法eclipse這次變得聰明點了如圖
   educitycn/img_///jpg>
  選擇預覽按鈕預先查看重構後的結果符合我們最初的目的
   educitycn/img_///jpg>
  選擇確定按鈕重構後的代碼片斷如下
  
  public String statement() {
  double totalAmount = ;
  int frequentRenterPoints = ;
  Enumeration rentals = _rentalselements();
  String result = Rental Record for + getName() + \n;
  
  while(rentalshasMoreElements()){
  Rental each = (Rental)rentalsnextElement();
  
  double thisAmount = amountFor(each);
  
  frequentRenterPoints ++;
  if((eachgetMovie()getPriceCode())==MovieNEW_RELEASE &&eachgetDaysRented()>)
  frequentRenterPoints ++;
  
  result += \t + eachgetMovie()getTitle() + \t +StringvalueOf(thisAmount) + \n;
  totalAmount += thisAmount;
  }
  
  result += Amount owed is + StringvalueOf(totalAmount) + \n;
  result += You earned + StringvalueOf(frequentRenterPoints) + frequent renter points;
  
  return result;
  }
  
  /**
  * @param each
  * @return
  */
  private double amountFor(Rental each) {
  double thisAmount = ;
  switch(eachgetMovie()getPriceCode()){
  case MovieREGULAR:
  thisAmount += ;
  if(eachgetDaysRented()>)
  thisAmount += (eachgetDaysRented())*;
  break;
  
  case MovieNEW_RELEASE:
  thisAmount += eachgetDaysRented()*;
  break;
  
  case MovieCHILDRENS:
  thisAmount += ;
  if(eachgetDaysRented()>)
  thisAmount += (eachgetDaysRented())*;
  break;
  }
  return thisAmount;
  }
  
  選中amountFor()的參數each在右鍵菜單中選擇重構/重命名在對話框中輸入新的名稱aRental選擇確定amountFor()中所有each的引用全部被替換成新的名稱用同樣的辦法修改amountFor()中的局部變量thisAmount為result重構後的amountFor()代碼如下
  
  /**
  * @param aRental
  * @return
  */
  private double amountFor(Rental aRental) {
  double result = ;
  switch(aRentalgetMovie()getPriceCode()){
  case MovieREGULAR:
  result += ;
  if(aRentalgetDaysRented()>)
  result += (aRentalgetDaysRented())*;
  break;
  
  case MovieNEW_RELEASE:
  result += aRentalgetDaysRented()*;
  break;
  
  case MovieCHILDRENS:
  result += ;
  if(aRentalgetDaysRented()>)
  result += (aRentalgetDaysRented())*;
  break;
  }
  return result;
  }
  
  重構第二步搬移金額計算代碼
  
  目的
  
   將函數amountFor()轉移到Rental類中並更名為getCharge()
  
   更新並替換所有對amountFor()的引用
  
  重構方法
  
  Move Method
  Change Method signatrue
  Inline Method
  Inline Temp
  
  方法
  
  選中函數amountFor()的定義在右鍵菜單中選擇重構/移動顯示參數設置對話框把新方法名改成getCharge按下確定按鈕Customer Class中的amountFor()函數被移動到Rental Class中並更名為getCharge()
   educitycn/img_///jpg>
  同時eclipse自動在Customer的amountFor()函數中添加一行對新函數的委托代碼
  
  private double amountFor(Rental aRental) {
  return aRentalgetCharge();
  }
  
  這行代碼會產生編譯錯誤原因是amountFor()的private型被傳遞到了新的方法中
  
  /**
  * @param this
  * @return
  */
  private double getCharge() {
  ……
  }
  
  繼續重構!選中getCharge()方法在右鍵菜單中選擇重構/更改方法特征符彈出參數選擇對話框把訪問修飾符從private改成publicEclipse的編譯錯誤提示自動消失
   educitycn/img_///jpg>
  回到Customer類把所有對amountFor()引用的地方替換成直接對getCharge()的引用選中Customer類的函數amountFor(Rental aRental)在右鍵菜單中選擇重構/內聯出現參數選擇對話框
   educitycn/img_///jpg>
  選擇確認按鈕引用amountFor()的地方被替換成對getCharge()的引用
  
  public String statement() {
  ……
  double thisAmount = eachgetCharge();
  ……
  }
  
  除去臨時變量thisAmount
  
  選中變量thisAmount在右鍵菜單中選擇重構/內聯重構預覽窗口如下可見達到了重構的目的按下確認按鈕重構代碼
   educitycn/img_///jpg>
  statement()代碼
  
  public String statement() {
  double totalAmount = ; // 總消費金額
  int frequentRenterPoints = ; // 常客積點
  Enumeration rentals = _rentalselements();
  String result = Rental Record for + getName() + \n;
  
  while(rentalshasMoreElements()){
  Rental each = (Rental)rentalsnextElement(); //取得一筆租借記錄
  
  // add frequent renter points(累加 常客積點)
  frequentRenterPoints ++;
  // add bouns for a two day new release rental
  if((eachgetMovie()getPriceCode())==MovieNEW_RELEASE && eachgetDaysRented()>)
  frequentRenterPoints ++;
  
  // show figures for this
From:http://tw.wingwit.com/Article/program/Java/ky/201311/11170.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.