Java程序员的代码重构之旅:从混乱到优雅

Java程序员的代码重构之旅:从混乱到优雅

作为一个Java程序员,你是否曾经面对过这样的场景?代码库如同一团乱麻,函数命名让人摸不着头脑,逻辑分散在各个角落,每次修改都像是在玩俄罗斯方块,生怕哪一行不小心就会导致整个系统崩溃。别担心,今天我们就来一场代码重构的冒险,把这段混乱不堪的代码变成优雅的典范。

重构前的代码:一团糟

让我们先看看这位程序员朋友最初写的代码吧:

public class PaymentService {
    public void processPayment(String paymentType, double amount, boolean isTaxDeducted) {
        if (paymentType.equals("credit")) {
            System.out.println("Processing credit card payment...");
            double finalAmount = amount;
            if (isTaxDeducted) {
                finalAmount = calculateTax(amount);
            }
            chargeCreditCard(finalAmount);
        } else if (paymentType.equals("debit")) {
            System.out.println("Processing debit card payment...");
            double finalAmount = amount;
            if (isTaxDeducted) {
                finalAmount = calculateTax(amount);
            }
            chargeDebitCard(finalAmount);
        } else {
            System.out.println("Unsupported payment type");
        }
    }

    private double calculateTax(double amount) {
        return amount * 0.05;
    }

    private void chargeCreditCard(double amount) {
        System.out.println("Charging credit card for " + amount);
    }

    private void chargeDebitCard(double amount) {
        System.out.println("Charging debit card for " + amount);
    }
}

这段代码虽然能正常工作,但存在几个问题:

  1. 重复代码:处理信用卡和借记卡支付的逻辑几乎完全一样,只是调用了不同的方法。
  2. 硬编码:"credit"和"debit"这些字符串被直接写在代码里,增加了维护成本。
  3. 可读性差:函数名不够直观,参数含义不明。

接下来,我们一步步将这段代码重构为更优雅的形式。

第一步:提取公共逻辑

首先,我们可以看到chargeCreditCard和chargeDebitCard这两个方法非常相似,都是根据金额进行扣款操作。我们可以将它们合并成一个通用的方法。

private void chargeCard(double amount, String cardType) {
    System.out.println("Charging " + cardType + " card for " + amount);
}

然后修改processPayment方法,统一调用这个新的chargeCard方法:

public void processPayment(String paymentType, double amount, boolean isTaxDeducted) {
    if ("credit".equals(paymentType)) {
        System.out.println("Processing credit card payment...");
        double finalAmount = amount;
        if (isTaxDeducted) {
            finalAmount = calculateTax(amount);
        }
        chargeCard(finalAmount, "credit");
    } else if ("debit".equals(paymentType)) {
        System.out.println("Processing debit card payment...");
        double finalAmount = amount;
        if (isTaxDeducted) {
            finalAmount = calculateTax(amount);
        }
        chargeCard(finalAmount, "debit");
    } else {
        System.out.println("Unsupported payment type");
    }
}

这样做的好处是减少了重复代码,同时让代码结构更加清晰。

第二步:使用策略模式

为了让代码更具扩展性和灵活性,我们可以引入策略模式。通过定义一个接口PaymentStrategy,为每种支付方式实现不同的策略。

interface PaymentStrategy {
    void execute(double amount);
}

class CreditCardPayment implements PaymentStrategy {
    @Override
    public void execute(double amount) {
        System.out.println("Charging credit card for " + amount);
    }
}

class DebitCardPayment implements PaymentStrategy {
    @Override
    public void execute(double amount) {
        System.out.println("Charging debit card for " + amount);
    }
}

接着修改PaymentService类,让它接受PaymentStrategy对象作为参数:

public class PaymentService {
    private PaymentStrategy strategy;

    public PaymentService(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void processPayment(double amount, boolean isTaxDeducted) {
        double finalAmount = amount;
        if (isTaxDeducted) {
            finalAmount = calculateTax(amount);
        }
        strategy.execute(finalAmount);
    }

    private double calculateTax(double amount) {
        return amount * 0.05;
    }
}

现在我们可以轻松添加新的支付方式,而无需修改现有代码。比如新增一个PayPal支付:

class PayPalPayment implements PaymentStrategy {
    @Override
    public void execute(double amount) {
        System.out.println("Processing PayPal payment for " + amount);
    }
}

第三步:增强代码的可读性

最后一步是优化代码的可读性。我们可以使用枚举类型来代替字符串常量,这样不仅能提高代码的安全性,还能减少拼写错误的可能性。

enum PaymentType {
    CREDIT, DEBIT, PAYPAL
}

public void processPayment(PaymentType type, double amount, boolean isTaxDeducted) {
    PaymentStrategy strategy;
    switch (type) {
        case CREDIT:
            strategy = new CreditCardPayment();
            break;
        case DEBIT:
            strategy = new DebitCardPayment();
            break;
        case PAYPAL:
            strategy = new PayPalPayment();
            break;
        default:
            throw new IllegalArgumentException("Invalid payment type");
    }
    
    double finalAmount = amount;
    if (isTaxDeducted) {
        finalAmount = calculateTax(amount);
    }
    strategy.execute(finalAmount);
}

通过这些改进,我们的代码不仅更加简洁、灵活,而且易于维护和扩展。更重要的是,它传达了一个重要的编程理念:不要害怕重构,因为好的代码就像一杯好酒,越陈越香。

总结

代码重构是一门艺术,也是一种责任。它不仅仅是为了让代码看起来美观,更是为了提升系统的可维护性和可扩展性。希望今天的重构之旅能给你带来一些启发,在未来的编程生涯中,勇敢地拿起重构工具,让每一行代码都闪耀着智慧的光芒。记住,优秀的程序员不仅要会写代码,还要会“修理”代码!