首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

提升 Java 代碼復用性的三大重構策略:從繼承到組合的範式轉移

     編輯:Java 程式設計入門

前言:繼承不是復用的銀彈

《Design Patterns》開宗明義:「Favor composition over inheritance」。類別繼承雖直觀,卻帶來強耦合、脆弱基底類別、方法爆炸等顽疾。本文提出三個漸進式重構策略,將「繼承式復用」轉化為「組合式復用」,實現更精準、靈活的代碼共享。

策略一:將實例方法提煉為靜態工具函數(函數式抽離)

痛點

想復用 Polygon 的 getPerimeter(),卻被迫繼承整個類別,連帶引入無關的 isConvex()、containsPoint() 及所有欄位。

重構前

class Polygon {
    public int getPerimeter() { ... }
    public boolean isConvex() { ... }
    public boolean containsPoint(Point p) { ... }
}

重構後:引入靜態工具類 pPolygon

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); }
}

class pPolygon {  // 小寫開頭標記:純函數容器,非領域實體
    static int computePerimeter(Polygon polygon) { ... }
    static boolean isConvex(Polygon polygon) { ... }
    static boolean containsPoint(Polygon polygon, Point p) { ... }
}

核心收益

  • 按需引用:客戶代碼直接呼叫 pPolygon.computePerimeter(poly),無需繼承 Polygon。
  • 零副作用:靜態方法僅依賴參數,不讀寫共享狀態,天然執行緒安全、易測試、易遷移。
  • 命名慣例:p 前綴(procedure/process)區分「函數容器」與「領域實體」,語義清晰。

策略二:參數類型「介面化」(多態參數化)

洞見

「我們針對介面編程而非實現編程,才能真正復用方法。若方法參數皆為介面,它就能操作編寫代碼時尚不存在的類別。」—— Allen Holub

重構示範

// 之前:綁定具體類別
static boolean contains(Rectangle rect, int x, int y) { ... }

// 之後:依賴介面
interface Rectangular { Rectangle getBounds(); }

static boolean contains(Rectangular rect, int x, int y) { 
    Rectangle r = rect.getBounds(); 
    // 邏輯不變,但現在接受所有實現 Rectangular 的物件
}

集合場景的決定性優勢

// 檢查集合中任意矩形是否重疊
static boolean areAnyOverlapping(Collection<? extends Rectangular> rects) {
    // 無法轉型為 Rectangular 介面,就無法統一訪問 getBounds()
    // 若參數為 Collection,則排除 RoundRect、ImageView 等潛在類別
}

介面參數將方法的適用域從「單一類別」擴展至「實現契約的所有類別」,這正是開放封閉原則(OCP)的具體體現。

策略三:選擇「最小完備介面」(介面隔離原則 ISP)

原則

參數介面應 恰好滿足方法需求,不多不少。介面越小,實現類越多,復用面越廣。

反例與正例

// 反例:Window 傳入過多無關能力
static boolean areOverlapping(Window w1, Window w2) { ... }

// 正例:僅需矩形邊界
static boolean areOverlapping(Rectangular r1, Rectangular r2) { ... }

單一方法介面:函數指標的物件化替身

interface SortComparison {
    boolean comesBefore(Object a, Object b);
}

static void sort(List list, SortComparison comp) {
    // 僅需比較邏輯,SortComparison 成為「策略鉤子」
}

此時介面不再是領域契約,而是 行為插槽,類比 C 函數指標、Java 8 Comparator、Kotlin 函數類型。

綜合應用:新式代碼組織圖譜

層級職責典型形式
領域實體封裝狀態與不變約束class Order { ... }
行為工具無狀態演算法、計算、驗證class pOrder { static BigDecimal calcTotal(Order o) }
策略介面定義可插拔行為契約interface PricingStrategy { Money apply(Order o); }
協調服務編排實體、工具、策略class OrderService { ... }

避坑指南:何時「不」適用

  • 表現層代碼:UI 綁定、事件處理、頁面編排——極強業務侷限性,復用意義不大。
  • 高度耦合的領域不變量:如 Order.place() 涉及狀態機轉換,不宜剝離為靜態函數。
  • 框架擴充點:Spring BeanPostProcessor、Servlet Filter 等需框架管理生命週期,不適用靜態工具化。

結語

三大策略層層遞進:函數抽離 → 介面參數化 → 最小介面,將代碼從「繼承樹」解放為「函數森林 + 介面網絡」。這不是否定 OOP,而是回歸 OOP 精髓——封裝變化點,釐清依賴方向。下次想寫 extends BaseUtil 時,請先問自己:「能不能改成 pUtil.staticMethod(this)?」

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved