代码重构

月伴飞鱼 2024-11-17 15:48:18
代码整洁
支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者!

代码重构的目的

代码重构是指在不改变代码功能的前提下,通过修改代码的内部结构和外部表现形式,来提高代码的可读性、可维护性、性能和可扩展性。

通常包括以下几个方面:

  • 改进代码的结构,使代码更加清晰简洁。
  • 消除代码中的重复部分,减少代码冗余。
  • 提高代码的可读性,使代码更加易于理解和维护。
  • 提高代码的性能,减少代码的执行时间和内存占用。
  • 改善代码的可扩展性,使代码更容易被扩展和修改。

如何保证重构过程中不会引入新的bug?

既然想要重构,就意味着要修改代码,修改代码就可能引入新的bug。

所以,重构只能保证设计的改进,而不能保证程序没有bug。

目前发现bug的有效手段就是充分有效的测试,而保证充分有效的测试的关键是单元测试的高覆盖率。

什么时候选择重构?什么时候选择重写?

这个问题只能个人判断,很难给出一个有共通性的同类情况。

不过,一些需要重写的代码肯定有迹象:

  • 例如:某个项目由于编程语言太老或者平台环境太老导致推进速度较慢,不适用于当前情况。
    • 此时,这种情况下,重构代码的作用微乎其微,就需要选择重写了。

代码重构的方法

方法提取:

一个方法不宜超过50行,超过50行的代码,就充斥着 代码坏味道。

方法提取是指将一段代码抽象出来形成一个方法。

这样做的好处是可以减少代码的重复,提高代码的可读性和可维护性。

提取变量:

提取变量是指将一段表达式抽象出来形成一个变量。

这样做的好处是可以减少代码的重复,提高代码的可读性和可维护性。

案例说明,重构前的代码:

public double calculateTotalAmount(List<InvoiceItem> items) {
    double totalAmount = 0;
    for (InvoiceItem item : items) {
        totalAmount += item.getPrice() * item.getQuantity();
    }
    if (totalAmount > 100) {
        totalAmount *= 0.9;
    }
    return totalAmount;
}

在上述代码中,计算每个项目的金额是通过 item.getPrice() * item.getQuantity() 表达式来实现的。

重构后的代码:

将这个表达式抽象成一个变量 itemAmount,使代码更变得加易于理解和维护。

public double calculateTotalAmount(List<InvoiceItem> items) {
    double totalAmount = 0;
    for (InvoiceItem item : items) {
        double itemAmount = item.getPrice() * item.getQuantity();
        totalAmount += itemAmount;
    }
    if (totalAmount > 100) {
        totalAmount *= 0.9;
    }
    return totalAmount;
}

重构条件语句:

核心思想:通过简化、合并或提取条件语句,使代码更加清晰和易于理解。

重构前的代码:

public boolean canCreateAccount(Customer customer) {
    boolean canCreate = true;
    if (customer.getAge() < 18) {
        canCreate = false;
    }
    if (customer.getAccountNumber() != null && customer.getAccountNumber().length() != 0) {
        canCreate = false;
    }
    if (customer.getCreditScore() < 500) {
        canCreate = false;
    }
    return canCreate;
}

代码中,判断客户是否有资格创建账户的过程是通过多个条件语句实现的,如果还有其他情况,只能通过添加if/else的方法实现。

这不符合一段优秀代码的定义,根据重构条件语句的方式对其重构。

重构后的代码:

将多个条件语句合并成一个方法 isCustomerEligible(),使代码更加清晰易读。

对于这种多分支的逻辑语句,有各种不同的重构方法,在日常开发工作中,对于多条件判断的重构,最常用的是设计模式中的策略模式,大部分判断逻辑,都可用策略模式进行重构。

public boolean canCreateAccount(Customer customer) {
    boolean canCreate = true;
    if (!isCustomerEligible(customer)) {
        canCreate = false;
    }
    return canCreate;
}
private boolean isCustomerEligible(Customer customer) {
    if (customer.getAge() < 18) {
        return false;
    }
    if (customer.getAccountNumber() != null && customer.getAccountNumber().length() != 0) {
        return false;
    }
    if (customer.getCreditScore() < 500) {
        return false;
    }
    return true;
}

提取抽象类:

指将多个类中的公共方法抽象出来形成一个抽象类,使得这些类可以继承这个抽象类来继承公共方法。

这样做的好处是可以减少重复代码,提高代码的复用性和可维护性。

重构前的代码:

public class SavingsAccount {
    private double balance;
    private double interestRate;
    public SavingsAccount(double balance, double interestRate) {
        this.balance = balance;
        this.interestRate = interestRate;
    }
    public double getBalance() {
        return balance;
    }
    public double getInterestRate() {
        return interestRate;
    }
    public double calculateInterest() {
        return balance * interestRate;
    }
}
public class CheckingAccount {
    private double balance;
    private double transactionFee;
    public CheckingAccount(double balance, double transactionFee) {
        this.balance = balance;
        this.transactionFee = transactionFee;
    }
    public double getBalance() {
        return balance;
    }
    public double getTransactionFee() {
        return transactionFee;
    }
    public double calculateTransactionFee() {
        return transactionFee;
    }
}

代码中,SavingsAccount 和 CheckingAccount 类有很多相同的方法,如 getBalance() 方法。

通过提取抽象类的方式对代码进行重构。

重构后的代码:

public abstract class Account {
    protected double balance;
    public Account(double balance) {
        this.balance = balance;
    }
    public double getBalance() {
        return balance;
    }
    public abstract double calculateInterest();
}
public class SavingsAccount extends Account {
    private double interestRate;
    public SavingsAccount(double balance, double interestRate) {
        super(balance);
        this.interestRate = interestRate;
    }
    public double getInterestRate() {
        return interestRate;
    }
    public double calculateInterest() {
        return balance * interestRate;
    }
}
public class CheckingAccount extends Account {
    private double transactionFee;
    public CheckingAccount(double balance, double transactionFee) {
        super(balance);
        this.transactionFee = transactionFee;
    }
    public double getTransactionFee() {
        return transactionFee;
    }
    public double calculateTransactionFee() {
        return transactionFee;
    }
}
支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者!