“注入”在构造函数注入和依赖注入中的含义是什么

时间:2018-02-16 16:40:20

标签: dependency-injection constructor-injection

我已阅读有关依赖注入的内容。然后来了

  • 构造函数注入,
  • 吸气剂注射
  • Setter Injection
  • 界面注入

它们与依赖注入有何不同,或者它们都相同? 注射在这里意味着什么?只是将所需的对象/参数提供给类?像构造注入一样意味着传递必需的参数作为构造函数参数?或者我错过了什么?

3 个答案:

答案 0 :(得分:3)

依赖注入是通过第三方提供类来为类提供依赖关系的行为。

构造函数注入是最常见的依赖注入形式。构造函数注入是通过将它们指定为类的构造函数的参数来静态定义所需依赖项列表的行为。

Setter Injection(a.k.a.属性注入)和Method Injection(接口注入是Method Injection的特化)是将依赖提供(或“注入”)到消费类中的替代形式。

据我所知,吸气剂注射不存在。 Getter只能检索值,而不能设置,这是Dependency Injection 的要求。

因此,构造函数注入,Setter注入和接口注入都是依赖注入的形式。构造函数注入是DI的最常见形式,它强制使用所有所需的依赖项创建类。因此,构造函数注入应该是您首选的DI形式。然而,有些情况下,方法注入或属性注入也是有意义的。这本书Dependency Injection in .NET second edition(由Mark Seemann和我自己)详细介绍了这些形式的DI(尤其是chapter 4)。

答案 1 :(得分:0)

然后Dagger 2中有@Inject构造函数,这有点不同,初级开发人员可能会误认为是。看起来像这样:

ListAdapter @Inject constructor() : RecyclerView.Adapter<ListViewHolder>() {
//code
}

上面是Kotlin,在Java中看起来像这样:

class ListAdapter extends RecyclerView.Adapter<ListViewHolder>() {

@Inject
public ListAdapter(Context context) {

}

}

Dagger 2的功能允许您生成@Provides,而无需在模块中实际编写@Provides函数/ void。

通过用inject注释构造函数,您还告诉dagger有一个名为X的类,并且需要实例化它。基本上与将其添加到模块中相同。

答案 2 :(得分:0)

依赖注入的三种形式是构造函数,设置器,接口[和第四个,上下文]。我从未听说过吸气剂注射剂,所以我不会提及它。注入只是对象或组件与另一个对象或组件(通常是类)之间的关联方式。如果没有依赖项注入,则组件具有任何形式的关联都被认为是“紧密耦合”的。例如,考虑不使用依赖项注入的此类(用Java编写):

public class Salesman implements Worker {
     private Car itemForSale;
     public Salesman() {
          itemForSale = new Car("BMW");
     }
     public void printItemSold() {
          System.out.println("The salesman sold a " + itemForSale.name() 
          + " at price $"+itemForSale.price());
     }
}

在这里,推销员类与汽车类紧密相关。考虑到推销员也可以实际上销售零件,工具和服务。但是,itemForSale字段是Car对象,并且此处的默认构造函数将itemForSale设置为Car对象。如果将构造函数更改为public Salesman(String carName, double carPrice),我们的耦合会稍微宽松一些,但是,这仍然不会使Salesman和Cars脱钩-Saleman对象的功能仍“依赖” Car对象。

现在,这是构造函数依赖项注入的示例:

public class Salesman implements Worker {
     private Item itemForSale;
     public Salesman(Item item){
          itemForSale = item;
     }
     public void printItemSold(){
          System.out.println("salesman sold a " + itemForSale");
     }
}

现在我们可以在另一个类中编写

Item car = new Car("Jeep", 8900); // the Car class implements the Item item class/interface
Salesman salesman = new Salesman(car);
salesman.printItemSold();

Item part = new Part("tires", 67.99); // the Part class also implements the Item class/interface
Salesman salesman = new Salesman(part);
salesman.printItemSold();

... and so on.

这里的主要好处(在这种简单情况下可能很难看到)是,Salesman对象不依赖于Car类。为了包含所有要出售的不同类型的对象,我们不需要Car字段,Part字段,Service字段等,也不需要实现

if (car != null) 
     printItemSold(car) 
else if (part != null)
     printItemSold(part)
...

相反,我们要做的只是简单地提供(或注入)推销员出售给Salesman对象的Item。

Setter注入的工作方式大致相同,只是它使用了setter而不是构造函数。如果我们想更改出售的对象而不必每次都制作一个新对象,这将是有益的。

public class Salesman implements Worker {
     private Item itemForSale;
     public Salesman() { }
     public void setItem(Item item){
          this.itemForSale = item;
     }
     ...
} 

现在我们可以做到:

Salesman salesman = new Salesman();
salesman.setItem(new Car("Toyota", 23938.23);
salesman.print();
salesman.setItem(new Service("oil change", 17.78);
salesman.print();

我认为可以肯定地说,构造函数注入通常与setter注入一起实现,因为一旦实现了前一种形式,就很容易实现后者。

因为我以前没有使用过接口注入,所以我不会去进行接口注入,并且可能会给您错误的信息。如果您碰巧正在使用Java Spring,请知道Spring仅利用构造函数和setter注入-而不是接口。

最后,上下文依赖注入并不是大多数人在使用术语依赖注入时所想到的。但是对我来说,这是我尝试学习依赖注入是什么时最关心的(很抱歉,如果以下解释没有帮助-我很难用Java Spring之外的其他方式进行解释)。假设您有一个复杂的对象,例如数据库连接,其中包含许多字段,并且应仔细管理其生命周期。

可以将其设置为类中的字段,对其进行配置,建立或打开,开始和结束事务,并确保在程序终止时将其关闭,所有你自己。但是,如果您要做的只是简单地声明您想要一个连接对象,然后为您管理该连接,那就太好了。该连接仅在需要时打开,当您调用connection.save(data)时,事务将自动开始并提交,并且在您终止程序时,无论什么情况,即使有异常或错误,连接也会自动关闭。错误。例如,在Java Spring中,这将仅在Connection类中包含一个@Component@Bean批注,然后在任何利用该连接的类中声明@Autowired Connection connection // the Connection will even be constructed for you

这已成为编程世界中的大事。要了解原因,请说您有一个接受一个Driver对象(如MySQLDriver,MSSQLDriver或PostgresDriver)的连接。当然,这些驱动程序中的每一个都有不同的实现方式,并且需要唯一的一组配置。但是,对于在声明类中要求的托管连接对象,从一个数据库切换到另一个数据库时,您需要做的就是利用一种构造函数或setter注入的形式:Connection conn = new Connection(MSSQLDriver);@Autowired Connection conn; conn.setDriver(PostgresDriver);可以节省数小时的时间并省去学习复杂的“样板”代码的需要,因为您要做的就是对我们的字段进行一次更改,并且将相应地管理您的对象。

仅供参考,这是一则“除非您解释,否则您不知道”的帖子,因此,如果我弄错了,请随时纠正我。