本頁使用了標題或全文手工轉換

代碼重構

維基百科,自由的百科全書
前往: 導覽搜尋

代碼重構英語:Code refactoring)指對軟體代碼做任何更動以增加可讀性或者簡化結構而不影響輸出結果。

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

重構代碼[編輯]

圖一
圖二

軟體工程學里,重構代碼一詞通常是指在不改變代碼的外部行為情況下而修改原始碼,有時非正式地稱為「清理乾淨」。在極限編程或其他敏捷方法學中,重構常常是軟體開發迴圈的一部分:開發者輪流增加新的測試和功能,並重構代碼來增進內部的清晰性和一致性。自動化的單元測試保證了重構不至於讓代碼停止工作。

重構既不修正錯誤,又不增加新的功能性。反而它是用於提高代碼的可讀性或者改變代碼內部結構設計,並且移除死代碼,使其在將來更容易被維護。重構代碼可以是結構層面抑或是語意層面,不同的重構手段施行時,可能是結構的調整或是語意的轉換,但前提是不影響代碼在轉換前後的行為。特別是,在現有的程式的結構下,給一個程式增加一個新的行為可能會非常困難,因此開發人員可能先重構這部分代碼,使加入新的行為變得容易。

一個重構的小範例是修改一個變數的名稱使其具有更明確的含義,例如從單個字母的「i」重構為「interestRate」(利率,圖一)。較複雜的重構是把一段if區段中的代碼變為一個子程式(圖二)。更複雜一點的重構是用多型性來替換if 條件式。「清理」代碼已經發生了幾十年,重構中最關鍵的認知是有意地「清理」代碼,透過從已知的紀錄里一些常用的重構方法清理代碼,把它從增加新功能分開,然後個別的對代碼進行測試(任何的行為改變都可能帶來錯誤)。新的實現切合實際需要以改善現有設計,並且不改變原軟體的意圖或行為。

重構面對業界調適接受方面的挑戰。首先,對重構長遠的影響需要更深入研究追蹤。又,重構存於資料庫輪廓(database schema)的商業邏輯層幾乎是不可能或者非常困難的。最後,對介面造成影響的重構可能造成程式開發上的困境,除非程式員有對所有使用者介面的存取權。例如,程式設計師若改變某實體中的方法名稱,他要麽必須對整個專案裡頭所有連結到舊名的參考都加以編輯,要麽屈服於繼續維護使用舊名的殘株殘瓦介面。而該舊名的介面於內部呼叫該方法的新名。

源流[編輯]

重構這個術語是從數字多項式因式分解類比而來[1]。如,x2 − 1可以被分解為(x + 1)(x − 1),這樣揭示了前面的形式不可見的內部結構(如兩個根+1和−1)。同樣,在軟體重構中,在可見結構上的改變通常會揭示原代碼中「隱藏」的內部結構。

上面數學的例子展示了「重構」的問題。一個表示式不盡然客觀地或者處處比另一個更好。它們每個強調不同的方程式的觀點,故其實用便多多少少隨著個別不同使用情況,以及各個數學家個性與風格變動。這個問題於軟體開發領域亦然;個別程式員可能對某既定演算法理想的程式形式實現會有不同的意見。

為了簡化測試,重構是分步驟完成的。當重構結束後,任何行為上的變化無疑都是錯誤並可透過除錯該程式的新行為個別修正。

馬丁·福勒的著作《重構》是一個經典參考書。雖然重構已經非正式的使用了很多年了,威廉·歐普迪克英語William Opdyke在1993年的博士論文[2]卻是第一篇著名的關於的重構的文章,即使所有的理論與機制長久以來就以程式轉換系統存在。所有這些資源提供了一種常用重構方法的型錄索引──所有重構方法需要描述,包括怎樣辨識你需要(或者不需要)套用該方法,以及如何套用的問題。

重構方法簡單列表[編輯]

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

  • 封裝成員變數(Encapsulate Field)—將僅限於本類使用的變數重寫成私有(private)成員變數,並提供存取方法(accessor method)。這種重構方式可以將與外部呼叫者無關的變數隱藏起來,減少代碼的耦合性,並減少意外出錯的機率。
  • 提取方法(Extract Method)—意思是將大段代碼中的一部分提取後,構成一個新方法。這種重構可以使整段程式的結構變得更清晰,從而增加可讀性。這也對函式(Function)通用。
  • 一般化類型(Generalize Type)—將多個類/函式共用的類型抽象出可以公用的基礎類別(base class),然後利用多型性追加每個類/函式需要的特殊函式。這種重構可以讓結構更加清晰,同時可以增加代碼的可維護性。
  • 函式歸父(Pull Up)—或譯函式上移,指的是方法從子類別移動到父類。
  • 函式歸子(Push Down)—或譯函式下移,指的是方法從父類移動到子類別。
  • 方法更名(Rename Method)—將方法名稱以更好的表達它的用途。
重構方法 重構前 重構後
封裝成員變數
 
class SomeClass {
public int memberA;
...
}
class SomeClass { 
private int memberA; 
public int getMemberA();
public void setMemberA(int a);
...
}
方法提取
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... 
}
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; 
}
一般化類型
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;
  }
}
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);

代碼重構自動化[編輯]

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

辭源[編輯]

首先使用「重構」一辭於出版文獻是於一篇文章:《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聯名出版[3]。William Opdyke的博士論文於「重構:物件導向框架」,伊利諾大學,1992年出版[2]。「重構」術語幾乎至其後確定。

就英文新造字學來說,代碼重構(Refactoring)清楚地來自數學上的分解(factoring)。

參見[編輯]

參考資料[編輯]

  1. ^ 英文重構(refactor)為「重新」(re-)與「(因式)分解」(factor)兩單詞的結合
  2. ^ 2.0 2.1 http://martinfowler.com/bliki/EtymologyOfRefactoring.html
  3. ^ http://www.cs.ucd.ie/staff/meloc/home/papers/thesis/Chapter2.pdf

參考書目[編輯]

外部連結[編輯]