利用多型重構為帶參方法
《重構之美》之二
我在閱讀遺留程式碼時,經常發現存在這樣一種情形。在一個類中存在兩個方法,它們做了相似的工作,區別僅在於方法內部某些物件的型別。例如:
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物件型別賦值
- 簡單談談方法過載和方法重寫(編譯時多型和執行時多型)編譯多型
- 程式碼重構之法——方法重構分析
- 程式碼重構與單元測試——重構6:使用“多型”取代條件表示式(九)多型
- c#重寫和多型C#多型
- 為什麼值型別不允許顯式定義無參建構函式型別函式
- vue帶參請求,登入時效(防止重複登陸)Vue
- 程式碼重構與單元測試——“提取方法”重構(三)
- 利用Mesos構建多工排程系統
- 何為Java 中的多型?Java多型
- 紮帶型接地卡的安裝方法
- ChameleonAdapter-利用註解快速完成多型別列表建立ChameleonAPT多型型別
- 如何利用資料架構帶動企業增長?架構
- Voodoo案例講解:跑酷遊戲型別解析與創新重構方法分享Odoo遊戲型別
- C語言結構體作為形參C語言結構體
- 為什麼說數字化轉型的解構、重構,是企業的資料命脈?
- MyBatis帶參查詢MyBatis
- 一次簡單易懂的多型重構實踐,讓你理解條件邏輯多型
- C# 帶引數帶互鎖多執行緒呼叫方法C#執行緒
- 利用 CSS Overview 皮膚重構優化你的網站CSSView優化網站
- 重構 001 - 刪除Java的Setter方法Java
- 一文帶你瞭解python中的多型Python多型
- 利用CSS改變圖片顏色的多種方法!CSS
- 方法的形參和實參
- 方法的實參和形參
- C++八股之函式過載與重寫-靜態多型與動態多型C++函式多型
- 為什麼多執行緒可以利用到多核?執行緒
- php多維陣列去除重複值的方法PHP陣列
- C#基礎:多型:基類可以定義並實現虛(virtual)方法,派生類可以重寫(override)這些方法...C#多型IDE
- 程式碼重構與單元測試——對方法的引數進行重構(五)
- SUSE 為雲原生、容器化應用提供多模架構平臺,助力企業 IT 轉型架構
- 利用 Laravel Macroable 特性優化多型引數傳遞的技巧分享LaravelMac優化多型
- 為什麼要重構?深入探討重構的原則、範圍和時機
- 如何利用Spring Cloud構建起自我修復型分散式系統SpringCloud分散式
- React Effects List大重構,是為了他?React
- 前端構建:3類13種熱門工具的選型參考前端
- 為什麼重寫 equals() 方法,一定要重寫 hashCode() 呢?| HashMapHashMap
- CodeIgniter3 獲取GET/POST/PUT/DELETE方法多種方式傳參delete
- 多型~多型