重构遗留代码
问题描述
接手一个 5 年历史的项目,核心订单处理类 OrderProcessor 有 3000 行代码,包含业务逻辑、数据访问、通知发送等所有功能。
需要在不影响现有功能的情况下重构这个类。
传统思路
- 硬着头皮读代码 - 花几天理解逻辑
- 画流程图 - 手动梳理业务流程
- 小心翼翼改动 - 改一点测一点,担心出问题
- 可能半途而废 - 风险太大,改不下去
预计耗时:1-2周,风险高
AI思维
第一步:让 AI 理解代码
这是一个遗留的订单处理类,有 3000 行代码。请帮我:
1. 梳理这个类的主要职责
2. 识别代码中的问题
3. 给出重构建议
[粘贴代码,或分段粘贴]第二步:AI 分析代码
AI 会给出:
职责分析
这个类违反了单一职责原则,至少包含以下职责:
- 订单验证(150-280行)
- 价格计算(281-450行)
- 库存处理(451-680行)
- 支付处理(681-920行)
- 通知发送(921-1100行)
- 数据持久化(分散各处)
问题识别
- God Class - 职责过多
- 大量重复代码 - 第 500 行和 850 行逻辑重复
- 硬编码 - 第 234 行硬编码折扣规则
- 缺少错误处理 - 多处可能的空指针
- 数据库操作散落 - 没有事务保证
重构策略 建议按职责拆分为以下类:
OrderProcessor (3000行)
↓ 拆分为
├── OrderValidator // 订单验证
├── PriceCalculator // 价格计算
├── InventoryManager // 库存管理
├── PaymentProcessor // 支付处理
├── NotificationService // 通知服务
└── OrderRepository // 数据访问第三步:安全重构计划
我需要一个安全的重构计划,要求:
1. 每一步都可以独立发布
2. 有回滚方案
3. 保证现有功能不受影响
请给我详细的步骤。AI 给出重构计划:
阶段一:准备工作(风险最低)
- 添加单元测试覆盖现有逻辑
java@Test void testCreateOrder_normalFlow() { // 记录现有行为作为基准 }
添加集成测试确保端到端正确
设置监控指标
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天 |
| 风险控制 | 凭经验 | 系统化方法 |
关键洞察
- 先理解后动手:让 AI 帮你快速理解遗留代码的结构
- 安全第一:要求 AI 给出可以分步发布的方案
- 测试先行:在重构前先建立测试基准
- 保留回滚能力:每一步都要可以回退
重构 Prompt 模板
请帮我重构这段遗留代码。
## 代码
[粘贴代码]
## 上下文
- 这个代码在生产环境运行
- 不能有任何功能回归
- 需要分步进行,每步可独立发布
请给我:
1. 代码问题分析
2. 重构目标结构
3. 分步重构计划
4. 每一步的具体代码和测试