利用多型重構為帶參方法
《重構之美》之二
我在閱讀遺留程式碼時,經常發現存在這樣一種情形。在一個類中存在兩個方法,它們做了相似的工作,區別僅在於方法內部某些物件的型別。例如:
public class WorkSheet{
public void fillHeader() {
Header header = createHeader();
for (String title:header.getTitles()) {
fillCell(title);
}
}
public 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{
public 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)對所有舊方法重複上述步驟,每次替換後,修改並測試
如果在呼叫新方法時,發現建立引數實參物件是一件麻煩事,可以考慮在原有類中引入一個建立新介面物件的工廠方法,從而對複雜的建立邏輯進行封裝。
本文轉自wayfarer51CTO部落格,原文連結:http://blog.51cto.com/wayfarer/440205,如需轉載請自行聯絡原作者
相關文章
- 【Java】程式碼重構時,為什麼禁止在方法內對物件型別的入參賦值Java物件型別賦值
- .NET重構(型別碼的設計、重構方法)型別
- 反射-通過反射獲取帶參構造方法並使用反射構造方法
- 物件導向基礎(1)--繼承 多型 重構物件繼承多型
- RAC重構型別型別
- 程式碼重構與單元測試——重構6:使用“多型”取代條件表示式(九)多型
- 程式碼重構之法——方法重構分析
- c#重寫和多型C#多型
- 重寫,隱藏,抽象,多型抽象多型
- java 建構函式內部的多型方法 完全剖析Java函式多型
- 反射-通過反射獲取無參無返回值成員方法、帶參帶返回值成員方法並使用反射
- Java中無參帶返回值方法的使用Java
- vue帶參請求,登入時效(防止重複登陸)Vue
- 為什麼值型別不允許顯式定義無參建構函式型別函式
- 專案重構之多Activity多FragmentFragment
- 基於演化博弈資料利用壓縮感知方法進行網路重構
- 何為Java 中的多型?Java多型
- 第六篇:為多型基類宣告虛解構函式多型函式
- 程式碼重構與單元測試——“提取方法”重構(三)
- Voodoo案例講解:跑酷遊戲型別解析與創新重構方法分享Odoo遊戲型別
- 紮帶型接地卡的安裝方法
- 利用Mesos構建多工排程系統
- C語言結構體作為形參C語言結構體
- Java重寫equals方法時為什麼要重寫hashcode方法Java
- MyBatis帶參查詢MyBatis
- 如何利用資料架構帶動企業增長?架構
- 為什麼說數字化轉型的解構、重構,是企業的資料命脈?
- 一次簡單易懂的多型重構實踐,讓你理解條件邏輯多型
- C# 帶引數帶互鎖多執行緒呼叫方法C#執行緒
- 利用OpenVSwitch構建多主機Docker網路Docker
- 利用 CSS Overview 皮膚重構優化你的網站CSSView優化網站
- C++八股之函式過載與重寫-靜態多型與動態多型C++函式多型
- 利用VC++獲取異構型資料庫庫結構資訊 (轉)C++資料庫
- 一文帶你瞭解python中的多型Python多型
- 重讀C++之一:封裝、繼承和多型C++封裝繼承多型
- php多維陣列去除重複值的方法PHP陣列
- 為什麼多執行緒可以利用到多核?執行緒
- 利用CSS改變圖片顏色的多種方法!CSS