重構之美之一利用多態重構為帶參方法

作者: 張逸  來源: 博客園  發布時間: 2010-12-05 17:51  閱讀: 904 次  推薦: 0   原文鏈接   [收藏]  

   我在閱讀遺留代碼時,經常發現存在這樣一種情形。在一個類中存在兩個方法,它們做了相似的工作,區別僅在于方法內部某些對象的類型。例如:

 
public class WorkSheet{
private void fillHeader() {
Header header
= createHeader();
for (String title:header.getTitles()) {
fillCell(title);
}
}
Private
void fillBody() {
CellGroup cellGroup
= createCellGroup();
for (Cell cell:cellGroup.getCells()) {
fillCell(cell.getText());
}
}
}

  方法fillHeader()和fillBody()的目的都是從對象中獲得字符串數組,然后將其填充到單元格中。區別在于,獲得字符串數組的對象并不相同。前者為Header對象,后者為CellGroup對象。我們可以為其提供一個抽象的接口,以實現代碼的有效重用:

 
public interface TextDataSource {
public String[] getTextArea();
}

  然后,讓Header和CellGroup類均實現該接口。由于CellGroup并沒有直接定義返回字符串數組的方法,而是通過返回的Cell對象獲得text值,因此,需要將這部分實現封裝到getTextArea()方法中:

 
public class Header implements TextDataSource {
@Override

public String[] getTextArea() {
//這里的實現即為原有的getTitles()實現
//可以保留原有的方法,并在本方法中指向該方法
//也可以利用Rename Method手法,直接更名該方法
}
}

public class CellGroup implements TextDataSource {
@Override

public String[] getTextArea() {
List
<String> textArea = new ArrayList<String>();
for (Cell cell:this.getCells()) {
textArea.add(cell.getText());
}

return textArea.toArray();
}
}

  現在,就可以重構原有的WorkSheet類了。

 
public class WorkSheet{
private void fillSheet(TextDataSource dataSource) {
for (String text:dataSource.getTextArea()) {
fillCell(text);
}
}
}

  具體需要填充什么內容,可以在調用fillSheet()方法時,根據傳入的參數對象來決定。經過重構之后,WorkSheet類中的重復代碼得到了移除,且具有了更好的擴展性。

  這一重構手法與Parameterize Method要解決的壞味道相似,同樣對相似方法提取了共同的參數,但實現的本質完全不同。它利用了多態的原理,通過對抽象方法體中的相似對象,抹去了不同類型對象之間的差異性,使得方法體中的相似結構能夠被抽取出來。

  我將這一重構手法命名為Parameterize Method by Polymorphism。讓我仿照Martin Fowler的風格,給出這一重構方式的作法(Mechanics):
  1)新建一個接口,并使原有方法中的差異對象實現該接口。
  2)如果原有對象的方法與該接口定義的方法簽名不同,則運用Rename Method。
  3)編譯。
  4)新建一個參數為新接口類型的方法,使它可以替換先前所有的重復方法。
  5)編譯。
  6)將對舊方法的調用替換為對新函數的調用。
  7)編譯,測試。
  8)對所有舊方法重復上述步驟,每次替換后,修改并測試

  如果在調用新方法時,發現創建參數實參對象是一件麻煩事,可以考慮在原有類中引入一個創建新接口對象的工廠方法,從而對復雜的創建邏輯進行封裝。

0
0
 
標簽:重構
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()