代碼重構

代碼重構（code refactoring）指改寫軟體代碼以增加可讀性或者簡化代碼結構而不影響輸出結果。

軟體重構需要藉助重構工具完成，重構工具能夠修改代碼同時修改所有引用該代碼的地方。在極限編程的方法學中，重構需要單元測試來支持。

## 重構代碼

<image>

<image>

在軟體工程學裡，重構代碼一詞通常是指在不改變代碼的外部行為情況下而修改原始碼。在極限編程或其他敏捷方法學中，重構常常是軟體開發中的一部分：開發者輪流增加新的測試和功能，並重構代碼來增進代碼間的清晰性和一致性。同時，自動化的單元測試保證了重構後的代碼仍然能夠正常運作。

重構既不修正錯誤，也不增加新的功能。它的目的是用於提高代碼的可讀性或者改變代碼內部結構與設計或者刪除死碼，使其在將來更容易進行維護和開發。重構代碼可以存在於結構層面或是語意層面，但前提是不影響代碼在轉換前後的功能。一種進行重構的典型案例是：一個程序在現有的邏輯結構下難以加入新的功能，因此開發人員可能會對代碼進行重構，以便日後繼續開發。

一個重構的小範例是修改一個變量的名稱使其具有更明確的含義，例如從單個字母的「i」重構為「interestRate」（利率，圖一）。一個較複雜的重構的例子是把一段if區塊中的代碼變為一個子程序（圖二）。更複雜一點的重構是用多態性來替換`if` 條件式。進一步還可重新設計程序的演算法。在重構中最關鍵的是去有意地「清理」代碼，把不同的功能分開，然後對重構後的代碼進行測試（任何對代碼的編輯都有可能引發錯誤）。新的實現方法需要切合實際地改善現有設計，並且不改變原軟體的功能或行為。

## 難點

代碼重構也面臨諸多的挑戰。首先，對重構長遠的影響需要在重構後才能進行深入研究和追蹤。其次，重構某些底層業務邏輯或是資料庫架構幾乎是不可能的。最後，對接口造成影響的重構可能造成程式開發上的困境。例如，程式設計師若改變某接口中的方法名稱，除非他或她要對所有客戶端中連結到舊方法名的參考都加以編輯，否則就只能繼續維護使用舊方法名的接口，並另外建立舊名對新名的映射。

## 源流

首先使用「重構」一辭於出版文獻是於一篇文章：《Refactoring: An Aid in Designing Application Frameworks and Evolving Object-Oriented Systems, Proceedings of the Symposium on Object Oriented Programming Emphasizing Practical Applications (SOOPPA)》，1990年9月，由William F. Opdyke與Ralph E. Johnson聯名出版。William Opdyke的博士論文於「重構：物件導向框架」，伊利諾大學，1992年出版。「重構」術語幾乎至其後確定。

重構這個術語是從數字與多項式的因式分解類比而來。如，x2 − 1可以被分解為(x + 1)(x − 1)，這樣更好的整理並展示了式子的性質（例如式子擁有兩個根+1和−1）。同樣，在軟體重構中，結構上的改變通常會揭示原代碼中曾經「隱藏」的內部結構。

上面多項式的例子很好地展示了「重構」的思路。但是，一個多項式的不同表示形式並沒有優劣之分，它們展現了多項式的不同性質。在不同情況下適合的表達形式不同，並且還會隨著使用者的個人習慣或理解變化。這個問題於軟體開發領域亦然：個別程式員可能對某既定演演算法的理想結構會有不同的意見。

## 重構方法列表

下面是一些代碼重構方式。長一點的清單可以在福勒的重構書找到。因為研究者們繼續努力不懈的發明以及實現重構，完整清單可能永遠都不存在。

- 成員變數封裝（Encapsulate Field）—將僅限於本類別使用的變量重寫成私有（private）成員變量，並提供訪問方法（accessor method）。這種重構方式可以將與外部調用者無關的變量隱藏起來，減少代碼的耦合性，並減少意外出錯的機率。
- 提取方法（Extract Method）—意思是將大段代碼中的一部分提取後，構成一個新方法。這種重構可以使整段程序的結構變得更清晰，從而增加可讀性。這也對函數（Function）通用。
- 一般化類（Generalize Type）—將多個類別/函數共用的類型抽象出可以公用的基類（base class），然後利用多態性追加每個類別/函數需要的特殊函數。這種重構可以讓結構更加清晰，同時可以增加代碼的可維護性。
- 函數歸父（Pull Up）—或譯函數上移，指的是方法從子類移動到父類。
- 函數歸子（Push Down）—或譯函數下移，指的是方法從父類移動到子類。
- 方法更名（Rename Method）—將方法名稱以更好的表達它的用途。

重構方法｜重構前｜重構後

封裝成員變量

```java
 
class SomeClass {
public int memberA;
...
}
```

```java
class SomeClass { 
private int memberA; 
public int getMemberA();
public void setMemberA(int a);
...
}
```

方法提取

```java
void Process(MyDataSet mds) 
{   
　// Step 1 ... 
　int result = 0;  
　if (mds.isReady) 
　{  
　　int data1 = mds.param[0]; 
　　int data2 = mds.param[1];  
　　// Preprocess... 
　　result = data1 % data2;  
　} 
　// Step 2... 
} 
```

```java
void Process(MyDataSet mds)
{  
　// Step 1 ... 
　int result = 0;  
　if (mds.isReady) 
　　result = CalculateMDS(mds.param[0], mds.param[1]);  
　// Step 2 ... 
}

int CalculateMDS(int data1, int data2)  
{ 
　　// Preprocess...  
　　return data1 % data2; 
}
```

一般化類型

```java
class Rectangle {
  private:
  int w, h;
  public:
  double Area(){
    return w*h;
  }
}
class Triangle {
  private:
  int w, h;
  public:
  double Area(){
    return w*h/2;
  }
} 
```

```java
class Polygon {
  private:
  int w, h;
  public:
  virtual double Area() = 0;
}
class Rectangle : public Polygon {
  double Area(){
  return w*h;
  }
}
class Triangle : public Polygon {
  double Area() {
    return w*h/2;
  }
}
```

方法更名｜`public double f(double m, double a); `｜`public double calculateForce(double mass, double acceleration);`

## 代碼重構自動化

許多軟體編輯器與整合環境支援重構自動化，又稱為重構瀏覽器。枚舉如下：

- IntelliJ IDEA（Java專用）
- Eclipse給Java用的開發包（JDK）
- NetBeans（Java專用）
- Visual Studio 2005（.NET專用）
- CodeGear Delphi
- Bicycle Repair Man （Python專用，可與emacs與vi共用）
- Refactoring Browser，Smalltalk專用

## 硬體重構

儘管代碼重構一詞最初只用於軟體代碼的重構，但近年來，硬體描述語言也出現了相應的代碼重構的概念。硬體重構（hardware refactoring）是對硬體描述語言中的代碼進行重構的簡稱。由於一般認為硬體描述語言與傳統程式語言有較大的區別，因此硬體重構被視為與傳統的代碼重構不同的領域。

研究者已經提出了模擬電路硬體描述語言（如VHDL-AMS）所使用的自動化重構方法。根據他們的研究，硬體重構會在保持原本代碼的仿真結果的同時，增進行為模型的可理解性、可擴展性和可重用性，並使得後續自動化編譯過程的邏輯綜合步驟可以產生更加符合預期的結構表示。此外，Synopsys公司的Mike Keating也研究了手動進行的數字電路硬體描述語言的重構。他所研究的目標是使複雜的硬體系統更易於理解，從而提高設計人員的生產力。

## 參考資料

### 來源

書籍

- 馬丁·福勒：《重構：改進現有代碼的設計》，Addison-Wesley Professional 1999, ISBN 978-0-201-48567-7
- William C. Wake：《重構練習冊》，Addison-Wesley, ISBN 978-0-321-10929-3
- Joshua Kerievesky：《重構到模式》，Addison-Wesley, ISBN 978-0-321-21335-8

## 外部連結

- 什麼是重構? （c2.com文獻）
- Martin Fowler的關於重構的主頁
- William F. Opdyke在1993年發表的博士論文
- 面向方面的重構，Ramnivas Laddad著
- 軟體重構的縱覽，Tom Mens和Tom Tourwé著
- 如何編寫難以維護的代碼，Roedy Green著
- 重構工具
- 重構 - alphabetical list
- 重構為模式的目錄
- 重構Java代碼
- 通用重構連結
- 微控制器軟體的重構
- Refuctoring —重構的反面（來自Waterfall2006會議的嘲諷）
- 重構文獻
- 重構相關短文