简介
“隐藏委托”(Hide Delegate)是一种重构手法,旨在减少类之间的耦合度。通过隐藏委托关系,客户端代码不需要直接与委托类交互,而是通过中间类来间接访问委托类的功能。这种重构手法可以提高代码的可维护性和可读性,同时减少客户端代码对委托类的依赖。
针对的症状(代码坏味道)
- 过度暴露的委托关系(Exposed Delegation)
- 客户端代码直接与委托类交互(Direct Dependency on Delegate)
隐藏委托(Hide Delegate)的详细步骤
- 识别委托关系
- 找到客户端代码直接访问委托类的地方。
- 确定中间类和委托类之间的关系。
- 创建中间类的方法
- 在中间类中创建一个方法,用于封装对委托类的访问。
- 确保新方法能够完成委托类的功能。
- 修改客户端代码
- 将客户端代码中对委托类的直接访问替换为对中间类方法的调用。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 手动测试:如果有必要,进行手动测试以验证功能的正确性。
- 代码审查
- 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
- 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明隐藏委托的影响。
示例
假设有一个类 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;
}
}
步骤如下:
- 识别委托关系:
- 客户端代码通过
Person类的getDepartment方法访问Department类,再通过Department类的getManager方法访问Manager类。
- 客户端代码通过
- 创建中间类的方法:
-
在
Person类中创建一个方法getManager,用于封装对Department类的访问:class Person { private Department department; public Person(Department department) { this.department = department; } public Manager getManager() { return department.getManager(); } }
-
- 修改客户端代码:
-
将客户端代码中对
Department类的直接访问替换为对Person类getManager方法的调用: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()); } }
-
- 测试:
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 代码审查:
- 让同事审查代码,确保没有引入新的问题。
练习
基础练习题
- 隐藏委托关系
-
给定以下 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); } }
-
进阶练习题
- 隐藏多层委托关系
-
在这段 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); } }
-
综合拓展练习题
- 多模块隐藏委托与代码审查模拟
-
考虑一个简单的 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); } }
-