Skip to content

重构遗留代码

问题描述

接手一个 5 年历史的项目,核心订单处理类 OrderProcessor 有 3000 行代码,包含业务逻辑、数据访问、通知发送等所有功能。

需要在不影响现有功能的情况下重构这个类。

传统思路

  1. 硬着头皮读代码 - 花几天理解逻辑
  2. 画流程图 - 手动梳理业务流程
  3. 小心翼翼改动 - 改一点测一点,担心出问题
  4. 可能半途而废 - 风险太大,改不下去

预计耗时:1-2周,风险高

AI思维

第一步:让 AI 理解代码

这是一个遗留的订单处理类,有 3000 行代码。请帮我:
1. 梳理这个类的主要职责
2. 识别代码中的问题
3. 给出重构建议

[粘贴代码,或分段粘贴]

第二步:AI 分析代码

AI 会给出:

职责分析

这个类违反了单一职责原则,至少包含以下职责:

  1. 订单验证(150-280行)
  2. 价格计算(281-450行)
  3. 库存处理(451-680行)
  4. 支付处理(681-920行)
  5. 通知发送(921-1100行)
  6. 数据持久化(分散各处)

问题识别

  1. God Class - 职责过多
  2. 大量重复代码 - 第 500 行和 850 行逻辑重复
  3. 硬编码 - 第 234 行硬编码折扣规则
  4. 缺少错误处理 - 多处可能的空指针
  5. 数据库操作散落 - 没有事务保证

重构策略 建议按职责拆分为以下类:

OrderProcessor (3000行)
         ↓ 拆分为
├── OrderValidator        // 订单验证
├── PriceCalculator      // 价格计算
├── InventoryManager     // 库存管理
├── PaymentProcessor     // 支付处理
├── NotificationService  // 通知服务
└── OrderRepository      // 数据访问

第三步:安全重构计划

我需要一个安全的重构计划,要求:
1. 每一步都可以独立发布
2. 有回滚方案
3. 保证现有功能不受影响

请给我详细的步骤。

AI 给出重构计划:

阶段一:准备工作(风险最低)

  1. 添加单元测试覆盖现有逻辑
java
@Test
void testCreateOrder_normalFlow() {
    // 记录现有行为作为基准
}
  1. 添加集成测试确保端到端正确

  2. 设置监控指标

java
// 记录关键指标,重构前后对比
metrics.counter("order.created").increment();
metrics.timer("order.process.time").record(...);

阶段二:提取策略模式(中等风险)

不改变 OrderProcessor,在旁边建立新结构:

java
// 新建验证器,使用策略模式
public interface OrderValidator {
    ValidationResult validate(Order order);
}

@Component
public class OrderValidatorChain implements OrderValidator {
    private List<OrderValidator> validators;

    public ValidationResult validate(Order order) {
        for (var validator : validators) {
            var result = validator.validate(order);
            if (!result.isValid()) return result;
        }
        return ValidationResult.success();
    }
}

阶段三:逐步迁移(分步进行)

使用「抽取-委托-删除」模式:

java
// Step 1: 抽取到新类
@Service
public class PriceCalculator {
    public BigDecimal calculate(Order order) {
        // 从 OrderProcessor 复制逻辑
    }
}

// Step 2: 旧类委托给新类
public class OrderProcessor {
    @Autowired
    private PriceCalculator priceCalculator;

    private BigDecimal calculatePrice(Order order) {
        return priceCalculator.calculate(order);
        // 原有代码注释保留,便于回滚
    }
}

// Step 3: 稳定后删除旧代码

每步发布检查:

  • [ ] 单元测试通过
  • [ ] 集成测试通过
  • [ ] 灰度发布观察指标
  • [ ] 确认无问题后继续下一步

第四步:生成重构代码

请帮我生成 PriceCalculator 的完整代码,基于原代码第 281-450 行的逻辑。要求:
1. 清晰的结构
2. 适当的错误处理
3. 单元测试

AI 生成清洁的代码:

java
@Service
@Slf4j
public class PriceCalculator {

    private final DiscountRuleRepository discountRuleRepository;

    public PriceCalculator(DiscountRuleRepository discountRuleRepository) {
        this.discountRuleRepository = discountRuleRepository;
    }

    /**
     * 计算订单总价
     * @param order 订单信息
     * @return 计算结果,包含明细
     */
    public PriceResult calculate(Order order) {
        Objects.requireNonNull(order, "Order cannot be null");

        BigDecimal subtotal = calculateSubtotal(order.getItems());
        BigDecimal discount = calculateDiscount(order);
        BigDecimal shipping = calculateShipping(order);
        BigDecimal total = subtotal.subtract(discount).add(shipping);

        return PriceResult.builder()
            .subtotal(subtotal)
            .discount(discount)
            .shipping(shipping)
            .total(total.max(BigDecimal.ZERO))  // 确保不为负
            .build();
    }

    private BigDecimal calculateSubtotal(List<OrderItem> items) {
        return items.stream()
            .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    private BigDecimal calculateDiscount(Order order) {
        List<DiscountRule> rules = discountRuleRepository.findApplicable(order);
        return rules.stream()
            .map(rule -> rule.apply(order))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    private BigDecimal calculateShipping(Order order) {
        // 满99免运费
        if (order.getSubtotal().compareTo(new BigDecimal("99")) >= 0) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal("10");  // 默认运费
    }
}
java
// 单元测试
@ExtendWith(MockitoExtension.class)
class PriceCalculatorTest {

    @Mock
    private DiscountRuleRepository discountRuleRepository;

    @InjectMocks
    private PriceCalculator calculator;

    @Test
    void calculate_normalOrder_returnsCorrectTotal() {
        Order order = createTestOrder(100, 2);  // 单价100,数量2
        when(discountRuleRepository.findApplicable(order))
            .thenReturn(Collections.emptyList());

        PriceResult result = calculator.calculate(order);

        assertThat(result.getSubtotal()).isEqualByComparingTo("200");
        assertThat(result.getShipping()).isEqualByComparingTo("0");  // 满99免运费
        assertThat(result.getTotal()).isEqualByComparingTo("200");
    }

    @Test
    void calculate_withDiscount_appliesCorrectly() {
        // ...
    }

    @Test
    void calculate_nullOrder_throwsException() {
        assertThatThrownBy(() -> calculator.calculate(null))
            .isInstanceOf(NullPointerException.class);
    }
}

结果对比

指标传统方式AI思维
理解代码时间2-3天1小时
重构计划制定半天30分钟
代码编写1周2天
风险控制凭经验系统化方法

关键洞察

  1. 先理解后动手:让 AI 帮你快速理解遗留代码的结构
  2. 安全第一:要求 AI 给出可以分步发布的方案
  3. 测试先行:在重构前先建立测试基准
  4. 保留回滚能力:每一步都要可以回退

重构 Prompt 模板

请帮我重构这段遗留代码。

## 代码
[粘贴代码]

## 上下文
- 这个代码在生产环境运行
- 不能有任何功能回归
- 需要分步进行,每步可独立发布

请给我:
1. 代码问题分析
2. 重构目标结构
3. 分步重构计划
4. 每一步的具体代码和测试

Released under the MIT License.