Java遗留代码重构:分步指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Java 遗留代码重构:从何入手以及如何不破坏项目



每位 Java 开发人员迟早都会遇到遗留代码。这可能是十年前编写的单体应用程序,或者是使用过时模式、缺乏测试和包含"魔法数字"的项目。重构此类代码并非易事,但对于维持系统的生命力来说绝对必要。



在本文中,我们将分析重构 Java 遗留代码的主要策略,展示具体示例,并提供实用建议,帮助您在不冒破坏生产环境风险的情况下改进代码。



为什么遗留代码需要重构?



遗留代码不仅仅是"旧代码"。它是这样的代码:



  • 难以维护和扩展
  • 没有足够的测试覆盖率
  • 包含重复和"代码坏味道"(code smells)
  • 使用过时的库和方法


重构可以改善代码的可读性、性能和可测试性。然而,主要规则是——不改变系统的外部行为。每个更改都必须是安全且可控的。



Java 遗留代码的重构策略



1. 创建由测试组成的保护网



在触碰代码之前,先编写测试。如果代码难以测试,这可能很困难。使用 Characterization Tests(基于当前行为的测试)方法。



示例:您有一个处理订单的方法:



public class OrderProcessor {    public double calculateTotal(Order order) {        double total = 0;        for (Item item : order.getItems()) {            if (item.getPrice() > 100) {                total += item.getPrice() * 0.9; // 10% 折扣            } else {                total += item.getPrice();            }        }        if (order.isPremium()) {            total *= 0.95; // 额外 5% 折扣        }        return total;    }}


编写一个记录当前行为的测试:



@Testpublic void testCalculateTotal_WithPremiumAndExpensiveItems() {    Order order = new Order();    order.addItem(new Item("Laptop", 1000));    order.addItem(new Item("Mouse", 50));    order.setPremium(true);        double expected = (1000 * 0.9 + 50) * 0.95; // 902.5    assertEquals(expected, new OrderProcessor().calculateTotal(order), 0.001);}


现在您有了一个"保护网"。可以放心重构,而不必担心改变逻辑。



2. 拆分大方法(Extract Method)



遗留代码最常见的问题之一是长达数百行的"怪物"方法。将它们拆分成小的、命名良好的方法。



重构前:



public void processInvoice(Invoice invoice) {    // 50 行验证代码    if (invoice.getCustomer() == null) throw new IllegalArgumentException();    if (invoice.getItems().isEmpty()) throw new IllegalStateException();    // ... 还有 20 行验证代码        // 100 行折扣和税费计算代码        // 80 行发送电子邮件和保存到数据库的代码}


重构后:



public void processInvoice(Invoice invoice) {    validateInvoice(invoice);    double total = calculateTotal(invoice);    saveInvoice(invoice, total);    sendConfirmationEmail(invoice);}

private void validateInvoice(Invoice invoice) { if (invoice.getCustomer() == null) throw new IllegalArgumentException(); if (invoice.getItems().isEmpty()) throw new IllegalStateException();}

private double calculateTotal(Invoice invoice) { // 计算逻辑 return invoice.getItems().stream() .mapToDouble(Item::getPrice) .sum();}

private void saveInvoice(Invoice invoice, double total) { // 保存}

private void sendConfirma

博客

书籍推荐