重构手法——函数行为重塑类 | 语意 | 用方法对象替换方法

43 阅读2分钟

简介

"用方法对象替换方法"是处理复杂方法的重构手法。通过将包含大量临时变量和复杂逻辑的方法转换为独立对象,将局部变量提升为对象字段,从而提高代码可维护性和可测试性。

针对的症状(代码坏味道)

  • 包含多个局部变量的长方法
  • 需要共享中间计算状态
  • 方法参数超过3个
  • 存在重复计算逻辑

用方法对象替换方法的详细步骤

  1. 创建方法对象类
    • 类名应反映原方法功能
    • 添加final字段保存原方法参数
  2. 迁移方法逻辑
    • 将局部变量转换为对象字段
    • 将原方法拆分为多个小方法
  3. 构造执行入口
    • 创建统一的execute/calculate方法
    • 保持与原方法相同的返回类型
  4. 替换原方法调用
    • 用方法对象实例化+执行替换原调用
    • 保持外部接口不变

示例

重构前代码:

class OrderCalculator {
    double calculatePrice(Order order, double taxRate, boolean isPremium) {
        double basePrice = order.getUnitPrice() * order.getQuantity();
        double discount = Math.max(0, basePrice - 1000) * 0.1;
        if (isPremium) discount *= 1.2;
        double tax = (basePrice - discount) * taxRate;
        return basePrice - discount + tax;
    }
}

重构步骤:

  1. 创建价格计算对象:

    class PriceCalculator {
        private final Order order;
        private final double taxRate;
        private final boolean isPremium;
    
        private double basePrice;
        private double discount;
        private double tax;
    
        PriceCalculator(Order order, double taxRate, boolean isPremium) {
            this.order = order;
            this.taxRate = taxRate;
            this.isPremium = isPremium;
        }
    
        double calculate() {
            calculateBasePrice();
            calculateDiscount();
            calculateTax();
            return basePrice - discount + tax;
        }
    
        private void calculateBasePrice() {
            basePrice = order.getUnitPrice() * order.getQuantity();
        }
    
        private void calculateDiscount() {
            discount = Math.max(0, basePrice - 1000) * 0.1;
            if (isPremium) discount *= 1.2;
        }
    
        private void calculateTax() {
            tax = (basePrice - discount) * taxRate;
        }
    }
    
  2. 重构原计算方法:

    class OrderCalculator {
        double calculatePrice(Order order, double taxRate, boolean isPremium) {
            return new PriceCalculator(order, taxRate, isPremium).calculate();
        }
    }
    

练习

基础练习题

  1. 简单方法对象化

    // 重构前
    class Geometry {
        double circleArea(double radius) {
            return Math.PI * radius * radius;
        }
    }
    

进阶练习题

  1. 多参数方法重构

    // 重构前
    class ReportGenerator {
        String generateReport(List<Data> data, boolean isHTML, Date date) {
            String header = isHTML ? "<h1>Report</h1>" : "REPORT";
            String body = processData(data, isHTML);
            String footer = isHTML ? "<footer>" + date + "</footer>" : date.toString();
            return header + body + footer;
        }
    }
    

综合拓展练习题

  1. 复杂业务逻辑封装

    // 重构前
    class LoanApproval {
        boolean approve(Application app, Policy policy) {
            double score = app.getIncome() * 0.3
                    + app.getCreditScore() * 0.7;
    
            if (policy.isStrict()) {
                score -= app.getDebt() * 0.1;
            }
    
            boolean approved = score > policy.getThreshold();
    
            if (approved && app.getAge() < 21) {
                approved = policy.allowYoungApplicants();
            }
    
            return approved;
        }
    }
    

代码审查要点

  1. 优点:

    • 分解复杂方法职责
    • 提高状态管理可见性
    • 支持分步执行和调试
  2. 潜在问题:

    • 避免过度包装简单方法
    • 注意对象生命周期成本
    • 保持与原方法的接口兼容