当前位置 : 主页 > 手机开发 > 其它 >

dependency-injection – 构造函数中的依赖注入容器

来源:互联网 收集:自由互联 发布时间:2021-06-22
为什么将容器放在构造函数中是如此糟糕?例如,您希望在另一个类(C)的构造函数中解析类B,因为您需要将类(B)与已解析的依赖项一起使用(您可以按照您希望的方式开始使用类C,就像它是
为什么将容器放在构造函数中是如此糟糕?例如,您希望在另一个类(C)的构造函数中解析类B,因为您需要将类(B)与已解析的依赖项一起使用(您可以按照您希望的方式开始使用类C,就像它是B但是解决了依赖关系).

Why putting a container in a constructor is so bad?

我想你的意思是将容器作为构造函数参数传递.这实际上是服务定位器模式的变体,在此上下文中被认为是反模式.您可能不想这样做有几个原因.

首先,类的用户只知道该类需要一个容器来解析其依赖关系.这些信息量完全等于没有信息,因为您仍然不知道该课程将依赖什么.你想为全班写一个单元测试吗?您必须查看类内部并查看它正在解析的类型,模拟它们并为每个测试初始化​​容器.这也意味着对某些代码的更改将使其编译但可能会破坏某些测试:例如,当新代码依赖于尚未在容器中注册的类时就是这种情况.

使用Service Locator时常见的次要影响是,在询问依赖关系时,您永远无法确定在运行时是否会收到异常.每个班级都注册正确吗?虽然某些容器提供了检查每个接口是否已注册的可能性,但并不意味着它已注册到正确的类型.例如,可能会发生一个类型在两个不同的实现中注册两次,并且很难注意到任何一段代码是否可以调用容器.

更好的解决方案是Composition Root pattern. This blog post还解释了为什么Service Locator可能不是一个好主意.

编辑根据新的发展:

显然,您正在使用第三方库,它依赖于具有默认构造函数的类.让我们假设你没有办法影响类的实例化,你必须让这个框架完成它的工作.请注意,这可能是一个很大的假设,请调查第三方库,以便首先进行此操作.乍一看,像ASP.NET WebForms和WCF这样的框架并没有给你很多机会,但是有一些方法可以减轻这些案例的痛苦.

I meant just to create the container in the constructor, add the
respective dependency to the container and resolve the object, which
can be done by simply creating instance of the dependency object and
use it to create the dependent object.

我可能会遗漏一些东西,但为什么你需要在构造函数中注册依赖项?难道你不能在构造函数中解决它,但在其他地方注册它?那仍然是一个服务定位器,但你至少会做错了.

Why doing so in the constructor is a bad idea and doing so elsewhere
is fine?

在任何地方,但在一个地方这样做是一个坏主意.为什么要在整个地方散布容器注册?如果您确实需要确定在运行时使用的接口的实现,请使用像Factory这样的东西.

那么,为什么不好呢?

>客户端类依赖于实现和接口,这并不比在构造函数中新建具体类更好.
>客户端类现在也依赖于容器,并且出现了Service Locator的问题(见上文),现在这种方法比新建具体类更糟糕.

正如@Steven所说,你失去了依赖注入的所有优点.真正的根本问题是:你为什么绝对想在这个地方做DI?您希望使用该方法的哪些优点?基于答案,可能有几种解决方案.我头顶的两个例子:

解决方案1:丢失由第三方库实例化的类的DI.

解决方案2:使用Bastard Injection Service Locator的组合.在这种情况下,两个错误可能是正确的.

public class MyClass
{
    public MyClass()
        : this(Container.Resolve<IDependency>())
    {
    }

    public MyClass(IDependency dep)
    {
    }
}

在这种情况下,您没有在构造函数中使用非本地依赖项,因为它由服务定位器解析,因此您不依赖于实现.

网友评论