代碼復用是軟件工程永恆追求。但盲目使用繼承往往導致脆弱的層級結構。本文提出三大重構策略,引導你從「繼承復用」轉向「組合復用」,從「依賴具體類」轉向「依賴接口」,構建高內聚、低耦合、高復用的代碼庫。
class Polygon {
public int getPerimeter() { ... }
public boolean isConvex() { ... }
public boolean containsPoint(Point p) { ... }
// 客戶代碼若只需 containsPoint,仍被迫繼承整個類
}
class Polygon {
public int getPerimeter() { return pPolygon.computePerimeter(this); }
public boolean isConvex() { return pPolygon.isConvex(this); }
public boolean containsPoint(Point p) { return pPolygon.containsPoint(this, p); }
}
// 職能類:名稱以小寫 p 開頭,標識純靜態工具類
class pPolygon {
static public int computePerimeter(Polygon polygon) { ... }
static public boolean isConvex(Polygon polygon) { ... }
static public boolean containsPoint(Polygon polygon, Point p) { ... }
}
「我們通過對接口而非類編程達到代碼復用。若方法所有參數都是接口引用,它就能操作編寫代碼時尚不存在的對象類型。可復用的是方法,而非傳入的對象。」
// 改前:綁定 Rectangle 具體類
static public boolean contains(Rectangle rect, int x, int y) { ... }
// 改後:依賴 Rectangular 接口
static public boolean contains(Rectangular rect, int x, int y) { ... }
interface Rectangular { Rectangle getBounds(); }
// 檢查集合中任意矩形是否重疊
static public boolean areAnyOverlapping(Collection rects) {
for (Rectangular r : rects) { // 多態遍歷
Rectangle bounds = r.getBounds();
// 重疊檢測邏輯...
}
}
若參數為 Collection,則只能處理 Rectangle 及其子類。接口參數使方法能處理所有實現 Rectangular 的類型(Ellipse、Polygon、自定義形狀等),復用性指數級提升。
參數接口應恰好滿足方法需求,越小越好。接口越小,實現類越多,方法適用面越廣。
// 改前:Window 接口過大,包含標題、圖標、事件等無關方法
static public boolean areOverlapping(Window w1, Window w2) { ... }
// 改後:只需矩形邊界信息
static public boolean areOverlapping(Rectangular r1, Rectangular r2) { ... }
// 排序比較器:只需一個比較方法
static public void sort(List list, SortComparison comp) { ... }
interface SortComparison {
boolean comesBefore(Object a, Object b); // 單一職責接口
}
SortComparison 專為 sort 服務,不可復用於其他場景——這正是「最小完備」的體現。
| 策略 | 核心手段 | 解決問題 | 適用場景 |
|---|---|---|---|
| 方法靜態化 | 實例方法 → 靜態工具方法 | 繼承耦合、職能混雜 | 工具算法、無狀態計算、通用邏輯 |
| 參數接口化 | 具體類參數 → 接口參數 | 類型綁定、擴展受限 | 集合處理、多態算法、框架擴展點 |
| 最小接口 | 大接口 → 最小職責接口 | 接口膨脹、實現困難 | 策略模式、回調、框架 SPI |
三大策略構成「現代 Java 復用鐵三角」:靜態方法分離職能、接口參數實現多態、最小接口最大化適用面。這不是拒絕 OOP,而是在恰當層次應用恰當抽象——數據用類封裝,行為用接口參數化,算法用靜態方法組合。如此代碼,歷久彌新。