重构手法——对象结构优化类 | 类关系解耦 | 内联函数

87 阅读3分钟

简介

“内联函数”(Inline Function)是一种重构手法,通过将函数调用替换为函数体中的实际代码,可以减少函数调用的开销并简化代码结构。这种方法适用于那些函数体非常简单且调用次数较少的情况。内联函数可以提高代码的可读性,但过度使用可能会导致代码重复和可维护性下降。

针对的症状(代码坏味道)

  • 函数体过于简单(Simple Function)
  • 函数调用开销过大(Excessive Function Call Overhead)
  • 函数调用次数较少(Infrequent Function Calls)

内联函数(Inline Function)的详细步骤

  1. 识别需要内联的函数
    • 找到函数体非常简单且调用次数较少的函数。
    • 确保内联后不会导致代码重复或可维护性下降。
  2. 替换函数调用
    • 将函数调用替换为函数体中的实际代码。
    • 确保替换后的代码逻辑与原来一致。
  3. 删除原函数
    • 删除不再需要的函数定义。
  4. 测试
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
    • 手动测试:如果有必要,进行手动测试以验证功能的正确性。
  5. 代码审查
    • 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
    • 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明内联函数的影响。

示例

假设有一个方法 calculateDiscount,它非常简单且只在一个地方被调用。我们希望对其进行“内联函数”的重构:

public class Order {
   private double price;
   private double discountRate;

   public Order(double price, double discountRate) {
      this.price = price;
      this.discountRate = discountRate;
   }

   public double calculateTotal() {
      double discount = calculateDiscount();
      return price - discount;
   }

   private double calculateDiscount() {
      return price * discountRate;
   }
}

步骤如下:

  1. 识别需要内联的函数:
    • calculateDiscount 方法非常简单且只在一个地方被调用。
  2. 替换函数调用:
    • calculateTotal 方法中的 calculateDiscount 调用替换为实际代码:

        public class Order {
         private double price;
         private double discountRate;
      
         public Order(double price, double discountRate) {
            this.price = price;
            this.discountRate = discountRate;
         }
      
         public double calculateTotal() {
            double discount = price * discountRate;
            return price - discount;
         }
      }
      
  3. 删除原函数:
    • 删除 calculateDiscount 方法。
  4. 测试:
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
  5. 代码审查:
    • 让同事审查代码,确保没有引入新的问题。

练习

基础练习题

  1. 内联简单函数
    • 给定以下 Java 代码,calculateTax 方法非常简单且只在一个地方被调用。请将其内联到 calculateTotal 方法中。

        public class Invoice {
         private double amount;
         private double taxRate;
      
         public Invoice(double amount, double taxRate) {
            this.amount = amount;
            this.taxRate = taxRate;
         }
      
         public double calculateTotal() {
            double tax = calculateTax();
            return amount + tax;
         }
      
         private double calculateTax() {
            return amount * taxRate;
         }
      }
      

进阶练习题

  1. 内联函数与返回值处理
    • 在这段 Java 代码中,getFormattedDate 方法非常简单且只在一个地方被调用。请将其内联到 printInvoiceDate 方法中,并确保返回值正确处理。

        import java.text.SimpleDateFormat;
      import java.util.Date;
      
      public class Invoice {
         private Date invoiceDate;
      
         public Invoice(Date invoiceDate) {
            this.invoiceDate = invoiceDate;
         }
      
         public void printInvoiceDate() {
            String formattedDate = getFormattedDate();
            System.out.println("Invoice Date: " + formattedDate);
         }
      
         private String getFormattedDate() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.format(invoiceDate);
         }
      }
      

综合拓展练习题

  1. 多模块内联函数与代码审查模拟
    • 考虑一个简单的 Java 电商系统,有 Product 类、Cart 类和 Order 类。Cart 类中的 calculateSubtotal 方法和 Order 类中的 calculateSubtotal 方法都非常简单且只在一个地方被调用。请对这些方法进行 “内联函数” 重构。

    • 假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。

        class Product {
         private double price;
      
         public Product(double price) {
            this.price = price;
         }
      
         public double getPrice() {
            return price;
         }
      }
      
      class Cart {
         private Product[] products;
      
         public Cart(Product[] products) {
            this.products = products;
         }
      
         public double calculateCartTotal() {
            double subtotal = calculateSubtotal();
            return subtotal;
         }
      
         private double calculateSubtotal() {
            double total = 0;
            for (Product product : products) {
               total += product.getPrice();
            }
            return total;
         }
      }
      
      class Order {
         private Product[] products;
         private double shippingCost;
      
         public Order(Product[] products, double shippingCost) {
            this.products = products;
            this.shippingCost = shippingCost;
         }
      
         public double calculateOrderTotal() {
            double subtotal = calculateSubtotal();
            return subtotal + shippingCost;
         }
      
         private double calculateSubtotal() {
            double total = 0;
            for (Product product : products) {
               total += product.getPrice();
            }
            return total;
         }
      }