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

70 阅读5分钟

简介

“内联类”(Inline Class)是一种重构手法,用于将一个类的功能合并到另一个类中,从而减少类的数量。这种重构手法通常用于当一个类不再承担足够的职责,或者其功能更适合放在另一个类中时。通过内联类,可以减少代码的复杂性,并提高代码的可读性和可维护性。

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

  • 类职责过少(Lazy Class):当一个类的职责过少,且其功能可以合理地合并到另一个类中时。
  • 过度分解(Over-Decomposition):当类的分解过于细致,导致代码难以理解和维护时。
  • 类之间的耦合度过高(High Coupling):当两个类之间的耦合度过高,且其中一个类的功能可以合理地合并到另一个类中时。

内联类(Inline Class)的详细步骤

  1. 识别需要内联的类
    • 寻找职责过少的类:在代码中找到那些职责过少,且其功能可以合理地合并到另一个类中的类。
    • 评估类的独立性:确保内联的类没有独立的职责,且其功能可以合理地合并到另一个类中。
  2. 将类的功能合并到目标类中
    • 移动字段:将需要内联的类的字段移动到目标类中。
    • 移动方法:将需要内联的类的方法移动到目标类中。
    • 更新引用:更新所有引用需要内联的类的地方,改为引用目标类。
  3. 删除原类
    • 删除原类:在确保所有功能都已合并到目标类中后,删除原类。
  4. 测试
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
    • 手动测试:如果有必要,进行手动测试以验证功能的正确性。
  5. 代码审查
    • 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
    • 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明内联类的影响。

示例

假设有一个类 Address,其功能可以合理地合并到 Person 类中,我们希望对其进行“内联类”的重构:

public class Person {
   private String name;
   private Address address;

   public Person(String name, Address address) {
      this.name = name;
      this.address = address;
   }

   public String getName() {
      return name;
   }

   public Address getAddress() {
      return address;
   }
}

public class Address {
   private String street;
   private String city;
   private String zipCode;

   public Address(String street, String city, String zipCode) {
      this.street = street;
      this.city = city;
      this.zipCode = zipCode;
   }

   public String getStreet() {
      return street;
   }

   public String getCity() {
      return city;
   }

   public String getZipCode() {
      return zipCode;
   }
}

步骤如下:

  1. 识别需要内联的类:
    • Address 类的职责过少,且其功能可以合理地合并到 Person 类中。
  2. 将类的功能合并到目标类中:
    • 移动字段:将 Address 类的字段移动到 Person 类中。

    • 移动方法:将 Address 类的方法移动到 Person 类中。

    • 更新引用:更新所有引用 Address 类的地方,改为引用 Person 类。

      public class Person {
         private String name;
         private String street;
         private String city;
         private String zipCode;
      
         public Person(String name, String street, String city, String zipCode) {
            this.name = name;
            this.street = street;
            this.city = city;
            this.zipCode = zipCode;
         }
      
         public String getName() {
            return name;
         }
      
         public String getStreet() {
            return street;
         }
      
         public String getCity() {
            return city;
         }
      
         public String getZipCode() {
            return zipCode;
         }
      }
      
  3. 删除原类:
    • 删除 Address 类。
  4. 测试:
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
  5. 代码审查:
    • 让同事审查代码,确保没有引入新的问题。

练习

基础练习题

  1. 内联类的字段和方法移动
    • 给定以下 Java 代码,Phone 类的功能可以合理地合并到 Contact 类中。请将 Phone 类的字段和方法移动到 Contact 类中,并删除 Phone 类。

      public class Contact {
         private String name;
         private Phone phone;
      
         public Contact(String name, Phone phone) {
            this.name = name;
            this.phone = phone;
         }
      
         public String getName() {
            return name;
         }
      
         public Phone getPhone() {
            return phone;
         }
      }
      
      public class Phone {
         private String number;
         private String type;
      
         public Phone(String number, String type) {
            this.number = number;
            this.type = type;
         }
      
         public String getNumber() {
            return number;
         }
      
         public String getType() {
            return type;
         }
      }
      

进阶练习题

  1. 内联类与引用更新
    • 在这段 Java 代码中,Email 类的功能可以合理地合并到 User 类中。请将 Email 类的字段和方法移动到 User 类中,并更新所有引用 Email 类的地方,改为引用 User 类。

      public class User {
         private String username;
         private Email email;
      
         public User(String username, Email email) {
            this.username = username;
            this.email = email;
         }
      
         public String getUsername() {
            return username;
         }
      
         public Email getEmail() {
            return email;
         }
      }
      
      public class Email {
         private String address;
         private boolean isVerified;
      
         public Email(String address, boolean isVerified) {
            this.address = address;
            this.isVerified = isVerified;
         }
      
         public String getAddress() {
            return address;
         }
      
         public boolean isVerified() {
            return isVerified;
         }
      }
      

综合拓展练习题

  1. 多模块内联与代码审查模拟

    • 考虑一个简单的 Java 电商系统,有 Product 类、Cart 类和 Order 类。Cart 类中的 Discount 类的功能可以合理地合并到 Cart 类中,同时 Order 类中的 Shipping 类的功能可以合理地合并到 Order 类中。
    • 请对这些类进行 “内联类” 重构,将 Discount 类和 Shipping 类的功能合并到 Cart 类和 Order 类中。
    • 假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
    class Product {
       private double price;
    
       public Product(double price) {
          this.price = price;
       }
    
       public double getPrice() {
          return price;
       }
    }
    
    class Cart {
       private Product[] products;
       private Discount discount;
    
       public Cart(Product[] products, Discount discount) {
          this.products = products;
          this.discount = discount;
       }
    
       public double calculateCartTotal() {
          double total = 0;
          for (Product product : products) {
             total += product.getPrice();
          }
          return discount.applyDiscount(total);
       }
    }
    
    class Discount {
       private double rate;
    
       public Discount(double rate) {
          this.rate = rate;
       }
    
       public double applyDiscount(double total) {
          return total * (1 - rate);
       }
    }
    
    class Order {
       private Product[] products;
       private Shipping shipping;
    
       public Order(Product[] products, Shipping shipping) {
          this.products = products;
          this.shipping = shipping;
       }
    
       public double calculateOrderTotal() {
          double total = 0;
          for (Product product : products) {
             total += product.getPrice();
          }
          return total + shipping.getShippingCost();
       }
    }
    
    class Shipping {
       private double cost;
    
       public Shipping(double cost) {
          this.cost = cost;
       }
    
       public double getShippingCost() {
          return cost;
       }
    }