重構是「在不改變外部行為前提下改善內部結構」的嚴格技術。擁有高覆蓋率單元測試是安全重構的前提;若無測試,先為核心/易錯區域補充功能測試作安全網。本文聚焦:如何透過重構發現代碼庫中隱藏的設計缺陷——基礎設施耦合與兩類複製。
框架提供 Helper 類誘導繼承(如 Struts ActionForm),換取自動表單填充、驗證等便利。代價:領域類強綁定框架,無法在非 Web 環境復用,繼承層次被佔用。
反模式:
public class ScheduleItem extends ActionForm { ... } // 領域類繼承框架類
改進:組合 + 介面隔離
public interface ScheduleItem { ... } // 語義契約
public class ScheduleItemImpl implements ScheduleItem { ... } // 純領域邏輯
public class ScheduleItemForm implements ScheduleItem { // 框架適配器
private ScheduleItem delegate; // 組合持有領域對象
// 委派實作介面方法,框架只見此類
}
領域類零依賴框架,自由部署於 Swing、Service Layer 等任意環境。原則:**框架依賴你的代碼,你的代碼不依賴框架。**
CPD (Copy/Paste Detector) 掃描 Struts 2 代碼庫發現大量跨文件複製,多集中於 Portlet 支持模組(PortletApplicationMap vs ApplicationMap),暗示擴展設計缺失——本應用繼承/組合消除重複。
另一典型案例:ApplicationMap.java 與 Sorter.java 共享 27 行匿名 Map.Entry 實作,唯一差異在 context.getAttribute() vs context.getInitParameter()。前兆代碼結構完全相同,參數化即可消除。
複製掩蓋了「將條目加入屬性集」這一慣用模式,重構提煉共用方法可公開此設計意圖。
定義:相同的空白,不同的值。代碼骨架完全一致(含縮排),僅字面量不同。典型例:Java Comparator 實作:
public class EmployeeNameComparator implements Comparator<Employee> {
public int compare(Employee e1, Employee e2) { return e1.getName().compareTo(e2.getName()); }
}
public class EmployeeSalaryComparator implements Comparator<Employee> {
public int compare(Employee e1, Employee e2) { return e1.getSalary() - e2.getSalary(); }
}
疊圖可見結構完全重合。屬性增多時,樣板代碼爆炸。
public class EmployeeSorter {
public void sort(List<DryEmployee> list, String criteria) {
Collections.sort(list, getComparatorFor(criteria));
}
private Method getSelectionCriteriaMethod(String field) { ... } // 反射取 getter
public Comparator<DryEmployee> getComparatorFor(final String field) {
return new Comparator<DryEmployee>() {
public int compare(DryEmployee o1, DryEmployee o2) {
Method m = getSelectionCriteriaMethod(field);
Object v1 = m.invoke(o1), v2 = m.invoke(o2);
return ((Comparable)v1).compareTo(v2);
}
};
}
}
新增屬性零代碼修改,動態生成 Comparator。權衡:反射版圈複雜度 8,單一 Comparator 為 1。**當屬性數 ≥ 9 時,反射版總複雜度更低**,且消除結構性複製風險。
JavaNCSS 測量提供客觀門檻:
團隊可依專案屬性設定臨界值,建立「重構觸發機制」。
重構不僅整理代碼,更是發現隱性設計的探針:
下篇將引入指標驅動重構,鎖定代碼庫中最需要重構、最可能藏匿設計寶藏的熱點區域。