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

重構筆記:方法層面重構模式 (3) - 解釋變數、分割暫時變數、移除參數賦值、以方法物件取代、替換演算法

     編輯:Java 相關知識

承接《重構》書籍方法層面重構手法,本文涵蓋第 5-9 條模式:引入解釋變數、分割暫時變數、移除參數賦值、以方法物件取代方法、替換演算法,附前後代碼對照與完整重構演示。

5. 引入解釋變數

複雜表達式拆解為具語意的暫時變數,提升可讀性。

// Before
double price() {
    return quantity * itemPrice
         - Math.max(0, quantity-500) * itemPrice * 0.05
         + Math.min(quantity * itemPrice * 0.1, 100.0);
}

// After
double price() {
    final double basePrice = quantity * itemPrice;
    final double quantityDiscount = Math.max(0, quantity-500) * itemPrice * 0.05;
    final double shipping = Math.min(quantity * itemPrice * 0.1, 100.0);
    return basePrice - quantityDiscount + shipping;
}

// 進階:萃取方法
double price() { return basePrice() - quantityDiscount() + shipping(); }
private double basePrice() { return quantity * itemPrice; }
private double quantityDiscount() { return Math.max(0, quantity-500) * itemPrice * 0.05; }
private double shipping() { return Math.min(quantity * itemPrice * 0.1, 100.0); }

6. 分割暫時變數

同一暫時變數承擔多重職責時,拆分為多個 final 變數。

// Before
double getDistanceTravelled(int time) {
    double result, acc = primaryForce/mass;
    int primaryTime = Math.min(time, delay);
    result = 0.5 * acc * primaryTime * primaryTime;
    int secondaryTime = time - delay;
    if (secondaryTime > 0) {
        double primaryVel = acc * delay;
        acc = (primaryForce+secondaryForce)/mass; // 復用 acc 變數
        result += primaryVel*secondaryTime + 0.5*acc*secondaryTime*secondaryTime;
    }
    return result;
}

// After
double getDistanceTravelled(int time) {
    double result;
    final double primaryAcc = primaryForce/mass;
    int primaryTime = Math.min(time, delay);
    result = 0.5 * primaryAcc * primaryTime * primaryTime;
    int secondaryTime = time - delay;
    if (secondaryTime > 0) {
        double primaryVel = primaryAcc * delay;
        final double secondaryAcc = (primaryForce+secondaryForce)/mass;
        result += primaryVel*secondaryTime + 0.5*secondaryAcc*secondaryTime*secondaryTime;
    }
    return result;
}

// 完整萃取
private double getPrimaryAcc() { return primaryForce/mass; }
private int getPrimaryTime(int time) { return Math.min(time, delay); }
private int getSecondaryTime(int time) { return time - delay; }

7. 移除參數賦值

參數不應被重新賦值,改用區域變數。

// Before
int discount(int inputVal, int quantity, int yearToDate) {
    if (inputVal > 50) inputVal -= 2;
    if (quantity > 100) inputVal -= 1;
    if (yearToDate > 10000) inputVal -= 4;
    return inputVal;
}

// After
int discount(int inputVal, int quantity, int yearToDate) {
    int result = inputVal;
    if (inputVal > 50) result -= 2;
    if (quantity > 100) result -= 1;
    if (yearToDate > 10000) result -= 4;
    return result;
}

8. 以方法物件取代方法

過長方法、大量區域變數難以萃取時,轉為獨立類別,區域變數變欄位,邏輯分解為多個私有方法。

// Before
class Account {
    int gamma(int inputVal, int quantity, int yearToDate) {
        int importantVal1 = (inputVal*quantity) + delta();
        int importantVal2 = (inputVal*yearToDate) + 100;
        if (yearToDate - importantVal1 > 100) importantVal2 -= 20;
        int importantVal3 = importantVal2 * 7;
        return importantVal3 - 2*importantVal1;
    }
}

// After
class Account {
    int gamma(int inputVal, int quantity, int yearToDate) {
        return new Gamma(this, inputVal, quantity, yearToDate).compute();
    }
}

class Gamma {
    private final Account account;
    private final int inputVal, quantity, yearToDate;
    private int importantVal1, importantVal2, importantVal3;

    Gamma(Account account, int inputVal, int quantity, int yearToDate) {
        this.account = account; this.inputVal = inputVal;
        this.quantity = quantity; this.yearToDate = yearToDate;
    }
    int compute() {
        importantVal1 = (inputVal*quantity) + account.delta();
        importantVal2 = (inputVal*yearToDate) + 100;
        if (yearToDate - importantVal1 > 100) importantVal2 -= 20;
        importantVal3 = importantVal2 * 7;
        return importantVal3 - 2*importantVal1;
    }
}

9. 替換演算法

以更清晰、高效的演算法替換現有實作,前提是測試保護下安全重構。

// 範例:排序、查找、計算邏輯替換
// 重點:有完整測試覆蓋時,大膽替換演算法本體

重構節奏提醒

  1. 先有測試 (綠燈)
  2. 小步重構,每步跑測試
  3. 命名即文檔:變數/方法名表達意圖
  4. 重構不改變外部行為,只改善內部結構

這些方法層面重構手法,是清理「代碼壞味道」的手術刀,持續練習才能內化為肌肉記憶。

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