重构手法——函数行为重塑类 | 语意 | 拆分循环

70 阅读2分钟

简介

"拆分循环"是优化代码结构的重要重构手法。通过将承担多重职责的循环分解为多个单一职责的循环,可以提高代码可读性、便于性能优化并增强可维护性。

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

  • 循环内处理多个不相关任务
  • 存在需要重复遍历的集合
  • 循环变量承担过多职责
  • 难以单独测试循环中的某个逻辑

拆分循环的详细步骤

  1. 识别多重职责
    • 查找循环中的独立任务块
    • 标记不同业务逻辑边界
  2. 准备中间数据结构
    • 创建临时集合存储中间结果
    • 提取共享变量到独立结构
  3. 拆分循环结构
    • 为每个职责创建独立循环
    • 保持业务逻辑不变
  4. 优化性能
    • 评估时间复杂度
    • 必要时合并同类操作

示例

重构前代码:

void processEmployees(List<Employee> employees) {
    double totalSalary = 0;
    List<Employee> managers = new ArrayList<>();

    for (Employee emp : employees) {
        // 计算总薪资
        totalSalary += emp.getSalary();
        // 收集经理
        if (emp.isManager()) {
            managers.add(emp);
        }
    }
}

重构后代码:

void processEmployees(List<Employee> employees) {
    // 第一个循环计算总薪资
    double totalSalary = employees.stream()
            .mapToDouble(Employee::getSalary)
            .sum();

    // 第二个循环收集经理
    List<Employee> managers = employees.stream()
            .filter(Employee::isManager)
            .collect(Collectors.toList());
}

练习

基础练习题

  1. 简单循环拆分

    // 重构前
    void analyzeOrders(List<Order> orders) {
        int count = 0;
        double total = 0;
        for (Order o : orders) {
            count++;
            total += o.getAmount();
        }
    }
    

进阶练习题

  1. 复合逻辑分离

    // 重构前
    void processData(List<Data> dataset) {
        Map<String, Integer> counters = new HashMap<>();
        List<Data> validData = new ArrayList<>();
    
        for (Data d : dataset) {
            if (d.isValid()) {
                validData.add(d);
                counters.merge(d.getType(), 1, Integer::sum);
            }
        }
    }
    

综合拓展练习题

  1. 性能敏感场景

    // 重构前
    void handleTransactions(List<Transaction> txns) {
        List<Transaction> frauds = new ArrayList<>();
        BigDecimal balance = BigDecimal.ZERO;
    
        for (Transaction t : txns) {
            balance = balance.add(t.getAmount());
            if (t.isSuspicious()) {
                frauds.add(t);
            }
        }
    }
    

代码审查要点

  1. 优点:

    • 提高代码可读性
    • 方便逻辑复用
    • 支持并行处理
  2. 潜在问题:

    • 注意时间复杂度变化
    • 控制中间数据结构大小
    • 保持原子操作完整性