我希望我能正确理解你的问题。
注入依赖
不,我们不会通过所有层传递依赖关系。我们只将它们传递给直接与它们对话的层。例如:
public class PaymentHandler {
private customerRepository;
public PaymentHandler(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public void handlePayment(CustomerId customerId, Money amount) {
Customer customer = customerRepository.findById(customerId);
customer.charge(amount);
}
}
public interface CustomerRepository {
public Customer findById(CustomerId customerId);
}
public class DefaultCustomerRepository implements CustomerRepository {
private Database database;
public CustomerRepository(Database database) {
this.database = database;
}
public Customer findById(CustomerId customerId) {
Result result = database.executeQuery(...);
// do some logic here
return customer;
}
}
public interface Database {
public Result executeQuery(Query query);
}
PaymentHandler
不知道Database
,它只谈CustomerRepository
。在存储库层注入Database
停止。
代码的可读性
在没有框架或库帮助的情况下进行手动注入时,我们最终可能会得到包含许多样板代码的工厂类,例如return new D(new C(new B(), new A());
在某些时候可能不太可读。为了解决这个问题,我们倾向于使用像Guice这样的 DI 框架来避免编写这么多工厂。
但是,对于实际执行工作/业务逻辑的类,它们应该更具可读性和可理解性,因为它们只与直接合作者交谈并完成他们需要做的工作。
单元测试
我假设“顶层”层是指PaymentHandler
班级。在这个例子中,我们可以创建一个存根CustomerRepository
类并让它返回一个Customer
我们可以检查的对象,然后将存根传递给 stub 以PaymentHandler
检查是否收取了正确的金额。
一般的想法是传入假合作者来控制他们的输出,这样我们就可以安全地断言被测类的行为(在这个例子中是PaymentHandler
类)。
为什么接口
正如上面评论中提到的,依赖接口而不是具体类更可取,它们提供更好的可测试性(易于模拟/存根)和更容易调试。
希望这可以帮助。