Skip to content

重构技巧:让烂代码重新焕发生命

代码不是写完就完事的,需要不断迭代改善。

Martin Fowler 说:"任何一个傻瓜都能写出计算机可以理解的代码,但只有写出人类能理解的代码,才是真正的程序员。"

重构,就是在不改变代码行为的前提下,让代码更易读、更易维护。

重构原则

  1. 测试先行:重构前确保有测试覆盖
  2. 小步前进:每次只改一点点,立即测试
  3. 保持功能:重构后行为不能变

常见重构手法

提取方法:长方法拆分

这是最常见的重构,把一个臃肿的方法拆成多个小方法:

java
// ❌ 重构前:方法做了太多事
public void processOrder(Order order) {
    // 校验订单
    if (order == null) throw new IllegalArgumentException();
    if (order.getItems().isEmpty()) throw new IllegalArgumentException("订单项不能为空");

    // 计算价格
    double total = 0;
    for (OrderItem item : order.getItems()) {
        total += item.getPrice() * item.getQuantity();
    }
    if (total > 1000) total *= 0.9;

    // 保存
    order.setTotal(total);
    orderRepository.save(order);

    // 发通知
    notificationService.sendOrderConfirmation(order);
}

// ✅ 重构后:每个方法只做一件事
public void processOrder(Order order) {
    validateOrder(order);
    double total = calculateTotal(order);
    applyDiscount(total);
    saveAndNotify(order);
}

private void validateOrder(Order order) {
    if (order == null) throw new IllegalArgumentException();
    if (order.getItems().isEmpty())
        throw new IllegalArgumentException("订单项不能为空");
}

private double calculateTotal(Order order) {
    return order.getItems().stream()
        .mapToDouble(item -> item.getPrice() * item.getQuantity())
        .sum();
}

private void applyDiscount(double total) {
    if (total > 1000) total *= 0.9;
}

private void saveAndNotify(Order order) {
    orderRepository.save(order);
    notificationService.sendOrderConfirmation(order);
}

提取变量:简化复杂表达式

java
// ❌ 复杂表达式难以理解
if (order.getStatus() == OrderStatus.PAID &&
    order.getAmount() > 1000 &&
    order.getUser().isVip()) {
    // 高级会员大额订单处理
}

// ✅ 提取变量:语义清晰
boolean isPaid = order.getStatus() == OrderStatus.PAID;
boolean isHighValue = order.getAmount() > 1000;
boolean isVip = order.getUser().isVip();

if (isPaid && isHighValue && isVip) {
    // 高级会员大额订单处理
}

引入参数对象:减少参数数量

java
// ❌ 参数过多
public void createUser(String firstName, String lastName, String email,
    String phone, String address, int age, boolean isActive) {
}

// ✅ 用 DTO 封装
public void createUser(UserCreateDTO dto) {
}

方法改名:让意图更清晰

java
// ❌ 模糊的方法名
public void process() { }      // process 什么?

// ✅ 清晰的动词 + 名词
public void processOrder() { }
public void validateInput() { }
public void sendNotification() { }

重构清单

开始重构前,先问自己:

问题检查项
有测试吗?如果没有,先补测试
要改多少?超过 5 处就分多次改
命名清晰吗?新名字能见名知意吗
职责单一吗?一个方法只做一件事

总结

  1. 测试先行:没有测试保护的重构是冒险
  2. 小步快跑:每次只改一处,立即验证
  3. 命名要清:好名字是好代码的标志
  4. 先拆后改:把大方法拆小了,再改细节

重构是代码的日常维护,和写代码一样重要。

基于 VitePress 构建