依赖注入在“链”上进一步延伸 - c#

我一直在阅读如何编写可测试的代码,偶然发现了Dependency Injection设计模式。

这种设计模式很容易理解,而且实际上没有任何内容,对象要求输入值,而不是自己创建值。

但是,现在我正在考虑如何在当前正在使用的应用程序中使用它,因此我意识到它存在一些复杂性。想象下面的例子:

public class A{

   public string getValue(){
      return "abc";
   }
}


public class B{
   private A a;

   public B(A a){
      this.a=a;
   }
   public void someMethod(){ 
      String str = a.getValue();
   }
}

单元测试someMethod ()现在将很容易,因为我可以创建A的模拟并让getValue()返回我想要的任何东西。

类B对A的依赖关系是通过构造函数注入的,但这意味着必须在类B之外实例化A,因此该依赖关系已移至另一个类。这将在许多层下重复进行,并且在某些时候必须进行实例化。

现在要问的问题是,在使用依赖注入时,您是否一直在所有这些层中传递依赖?这样会使代码的可读性和调试时间变得更短吗?而当您到达“顶层”时,您将如何对该类进行单元测试?

参考方案

希望我能正确理解您的问题。

注入依赖

不,我们不会将依赖关系传递给所有层。我们仅将它们传递给直接与它们交谈的图层。例如:

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());)的Factory类,在某些情况下,这些代码可能难以理解。为了解决这个问题,我们倾向于使用像Guice这样的DI框架来避免编写太多工厂。

但是,对于实际执行工作/业务逻辑的类,它们应该更具可读性和可理解性,因为它们仅与直接合作者交谈并完成他们需要做的工作。

单元测试

我认为“顶层”是指PaymentHandler类。在此示例中,我们可以创建存根CustomerRepository类,并让其返回我们可以检查的Customer对象,然后将存根传递给PaymentHandler以检查是否收取了正确的金额。

通常的想法是传递假的合作者来控制其输出,以便我们可以安全地断言被测类的行为(在本例中为PaymentHandler类)。

为什么要界面

正如上面的评论中提到的那样,最好是依赖于接口而不是具体的类,它们提供了更好的可测试性(易于模拟/存根)和更容易的调试。

希望这可以帮助。

可以导入Java类时为什么要使用依赖注入? - java

有人可以向我解释一下,当您只需要导入一个Java类时,为什么我们需要使用spring的依赖注入:import com.package.somejavaclass 我只是想知道为什么? 参考方案 DI和IoCDependency Injection(和Inversion of Control)与import无关。依赖注入使您可以制定运行时决策,而不是编译时决策…

依赖项注入,初始化后的不变性 - java

我希望能够指定对象的成员变量在对象被“初始化”后是不可变的,这对我来说意味着在注入任何依赖项之后,并且已经执行了它只能执行的任何其他初始化操作DI之后。是否有满足我兴趣的语言-以这种方式形式化DI,初始化和支持不变性?使它们成为语言的一部分可能很愚蠢;也许不会。我不确定。今天,我使用Java进行编程,但是我几乎无法使用“final”,因为这些阶段发生在构造函…

子组件与组件的依赖关系 - java

我从此文档https://google.github.io/dagger/api/latest/dagger/Component.html中读取了SubComponents和Component Dependencies之间的区别,并也阅读了此线程Dagger 2 subcomponents vs component dependencies有人可以帮我举例说…

Java:“自动装配”继承与依赖注入 - java

Improve this question 我通常以常见的简单形式使用Spring框架: 控制器服务存储库通常,我会在CommonService类中放一个通用服务,并使所有其他服务扩展到类中。一个开发人员告诉我,最好在每个服务中插入CommonClass而不是使用继承。我的问题是,有一个方法比另一个更好吗? JVM或性能是否会受到另一个影响?更新资料Comm…

LeetCode题解计算机为什么是基于二进制的?

可以是三进制么?二进制有什么好处?题解:为什么叫电子计算机?算盘应该没有二进制