重构手法——对象结构优化类 | 类关系解耦 | 隐藏委托

63 阅读4分钟

简介

“隐藏委托”(Hide Delegate)是一种重构手法,旨在减少类之间的耦合度。通过隐藏委托关系,客户端代码不需要直接与委托类交互,而是通过中间类来间接访问委托类的功能。这种重构手法可以提高代码的可维护性和可读性,同时减少客户端代码对委托类的依赖。

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

  • 过度暴露的委托关系(Exposed Delegation)
  • 客户端代码直接与委托类交互(Direct Dependency on Delegate)

隐藏委托(Hide Delegate)的详细步骤

  1. 识别委托关系
    • 找到客户端代码直接访问委托类的地方。
    • 确定中间类和委托类之间的关系。
  2. 创建中间类的方法
    • 在中间类中创建一个方法,用于封装对委托类的访问。
    • 确保新方法能够完成委托类的功能。
  3. 修改客户端代码
    • 将客户端代码中对委托类的直接访问替换为对中间类方法的调用。
  4. 测试
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
    • 手动测试:如果有必要,进行手动测试以验证功能的正确性。
  5. 代码审查
    • 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
    • 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明隐藏委托的影响。

示例

假设有一个类 Person,它通过 Department 类访问 Manager 类。我们希望隐藏 Person 类对 Department 类的直接依赖:

class Person {
   private Department department;

   public Person(Department department) {
      this.department = department;
   }

   public Department getDepartment() {
      return department;
   }
}

class Department {
   private Manager manager;

   public Department(Manager manager) {
      this.manager = manager;
   }

   public Manager getManager() {
      return manager;
   }
}

class Manager {
   private String name;

   public Manager(String name) {
      this.name = name;
   }

   public String getName() {
      return name;
   }
}

步骤如下:

  1. 识别委托关系:
    • 客户端代码通过 Person 类的 getDepartment 方法访问 Department 类,再通过 Department 类的 getManager 方法访问 Manager 类。
  2. 创建中间类的方法:
    • Person 类中创建一个方法 getManager,用于封装对 Department 类的访问:

        class Person {
         private Department department;
      
         public Person(Department department) {
            this.department = department;
         }
      
         public Manager getManager() {
            return department.getManager();
         }
      }
      
  3. 修改客户端代码:
    • 将客户端代码中对 Department 类的直接访问替换为对 PersongetManager 方法的调用:

        public class Main {
         public static void main(String[] args) {
            Manager manager = new Manager("John Doe");
            Department department = new Department(manager);
            Person person = new Person(department);
      
            // 重构前
            // Manager m = person.getDepartment().getManager();
      
            // 重构后
            Manager m = person.getManager();
            System.out.println("Manager's name: " + m.getName());
         }
      }
      
  4. 测试:
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
  5. 代码审查:
    • 让同事审查代码,确保没有引入新的问题。

练习

基础练习题

  1. 隐藏委托关系
    • 给定以下 Java 代码,Client 类直接访问 Service 类的 Database 对象。请将 Client 类对 Database 的直接访问隐藏起来。

        class Client {
         private Service service;
      
         public Client(Service service) {
            this.service = service;
         }
      
         public void executeQuery(String query) {
            Database db = service.getDatabase();
            db.execute(query);
         }
      }
      
      class Service {
         private Database database;
      
         public Service(Database database) {
            this.database = database;
         }
      
         public Database getDatabase() {
            return database;
         }
      }
      
      class Database {
         public void execute(String query) {
            System.out.println("Executing query: " + query);
         }
      }
      

进阶练习题

  1. 隐藏多层委托关系
    • 在这段 Java 代码中,Client 类通过 Service 类访问 Database 类的 Connection 对象。请将 Client 类对 Connection 的直接访问隐藏起来。

        class Client {
         private Service service;
      
         public Client(Service service) {
            this.service = service;
         }
      
         public void executeQuery(String query) {
            Connection conn = service.getDatabase().getConnection();
            conn.execute(query);
         }
      }
      
      class Service {
         private Database database;
      
         public Service(Database database) {
            this.database = database;
         }
      
         public Database getDatabase() {
            return database;
         }
      }
      
      class Database {
         private Connection connection;
      
         public Database(Connection connection) {
            this.connection = connection;
         }
      
         public Connection getConnection() {
            return connection;
         }
      }
      
      class Connection {
         public void execute(String query) {
            System.out.println("Executing query: " + query);
         }
      }
      

综合拓展练习题

  1. 多模块隐藏委托与代码审查模拟
    • 考虑一个简单的 Java 电商系统,有 Customer 类、Order 类和 Payment 类。Customer 类通过 Order 类访问 Payment 类的 Transaction 对象。请对这些类进行 “隐藏委托” 重构,将 Customer 类对 Transaction 的直接访问隐藏起来。

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

        class Customer {
         private Order order;
      
         public Customer(Order order) {
            this.order = order;
         }
      
         public void makePayment(double amount) {
            Transaction transaction = order.getPayment().getTransaction();
            transaction.process(amount);
         }
      }
      
      class Order {
         private Payment payment;
      
         public Order(Payment payment) {
            this.payment = payment;
         }
      
         public Payment getPayment() {
            return payment;
         }
      }
      
      class Payment {
         private Transaction transaction;
      
         public Payment(Transaction transaction) {
            this.transaction = transaction;
         }
      
         public Transaction getTransaction() {
            return transaction;
         }
      }
      
      class Transaction {
         public void process(double amount) {
            System.out.println("Processing payment of amount: " + amount);
         }
      }