依赖注入通过构造函数和属性setter?(Dependency injection through

2019-07-20 09:47发布

我重构一个类,并增加了新的依赖于它。 该班目前正在其现有的依赖于构造函数。 所以为了保持一致性,我的参数添加到构造函数。
当然,也有单元测试的几个子类加得更多,所以现在我打的绕来绕去改变一切,以匹配构造的游戏,它采取的年龄。
这让我觉得用与setter方法的属性是越来越依赖的一个更好的办法。 我不认为注入的依赖应该是接口构造类的一个实例的一部分。 您添加一个依赖,现在所有的用户(子类和任何直接实例你)突然知道。 那感觉就像封装的休息。

这似乎不符合这里的现有代码的模式,所以我期待找出普遍的共识是什么,构造与性能的优劣。 使用属性setter更好?

Answer 1:

这得看情况 :-)。

如果类不能没有依赖性完成自己的工作,然后将其添加到构造函数。 这个班的新的依赖,所以你想你的变化打破东西。 此外,在创建未完全初始化一个类(“两步结构”)是一种抗图案(IMHO)。

如果类可以不依赖工作,二传手是好的。



Answer 2:

一类的用户都应该知道一个给定类的相关性。 如果我有,例如,连接到数据库,并没有提供注入持久层依赖的手段一类,用户永远不会知道,到数据库的连接必须是可用的。 但是,如果我改变构造我让用户知道有持久层的依赖关系。

另外,为了防止自己不必改变每次使用旧的构造,简单地套用构造函数链为新老构造之间的临时桥。

public class ClassExample
{
    public ClassExample(IDependencyOne dependencyOne, IDependencyTwo dependencyTwo)
        : this (dependnecyOne, dependencyTwo, new DependnecyThreeConcreteImpl())
    { }

    public ClassExample(IDependencyOne dependencyOne, IDependencyTwo dependencyTwo, IDependencyThree dependencyThree)
    {
        // Set the properties here.
    }
}

一个依赖注入的点是为了揭示了什么依存关系类有。 如果类有太多的依赖,那么它可能是时间对于一些重构发生:是否类的每一个方法使用所有的依赖? 如果不是,那么这是一个很好的起点,看看那里的类可以被分离。



Answer 3:

当然,将在构造意味着您可以一次验证所有。 如果您分配东西放到只读域那么您对直接从施工时间的对象的依赖性一些保证。

这是一个真正的痛苦,增加新的依赖,但至少这样的编译器保持抱怨,直到它是正确的。 这是一个很好的事情,我想。



Answer 4:

如果你有大量可选的依赖(这已经是一个气味),那么可能setter注入是要走的路。 构造函数注入更好的表现出你的依赖,虽然。



Answer 5:

一般优选的方法是尽可能地使用构造函数注入。

构造函数注入准确指出什么是所需的依赖关系为对象,以正常工作 - 没有什么比newing了一个对象,并为它调用方法时,因为一些依赖没有设置它摔碎更恼人。 通过构造函数返回的对象应该是处于工作状态。

试着只有一个构造函数,它使设计简单,避免了歧义(如果不是人类,为DI容器)。

您可以使用属性注入时,你有什么马克塞曼调用本地默认在他的“在.NET依赖注入”的书:依赖是可选的,因为你可以提供一个优良的工作实现,但要允许调用者指定一个不同的,如果需要。

(下面前回答)


我认为,构造函数注入是更好,如果注射是强制性的。 如果这增加了太多的构造,可以考虑使用,而不是构造工厂。

该setter注入是很好,如果注射是可选的,或者如果你想改变它中途低谷。 我一般不喜欢setter方法,但它是一个爱好问题。



Answer 6:

这在很大程度上是个人喜好的问题。 我个人倾向于选择setter注入,因为我相信它给你的,你可以在运行时替换的实现方式更具灵活性。 此外,有很多参数的构造不干净,在我看来,并在构造函数中提供的参数应限于非可选参数。

只要类接口(API)是什么它需要执行其任务明确,你是好。



Answer 7:

我个人比较喜欢提取并改写 “模式”在构造函数中注入依赖,主要是为了在你的问题中列出的原因。 您可以设置属性为virtual ,然后覆盖在派生类可测试的实现。



Answer 8:

我更喜欢构造函数注入,因为它有助于“强制执行”一类的依赖性要求。 如果是在c'tor,消费者有权设置对象获取应用程序进行编译。 如果您使用setter注入他们可能不知道他们有直到运行时的问题 - 而根据不同的对象,它可能是在运行时已晚。

我仍然使用setter注入不时时被注入的对象可能需要一堆作品本身,就像初始化。



Answer 9:

我perfer构造函数注入,因为这似乎是最合理的。 这就像说,我的类需要这些依赖关系来完成其工作。 如果它的一个可选的依赖则性质似乎是合理的。

我还使用属性注射设定的东西,容器没有这样的引用为ASP.NET视图上的主持人使用的容器中创建。

我不认为它打破封装。 内部运作应该保持内部和依赖关系处理不同问题。



Answer 10:

一种选择可能是值得考虑的是组成复杂的多依赖了简单的单一依赖。 也就是说,定义复合依赖额外的课程。 这使事情变得更容易一些WRT构造注射 - 较少的参数每次通话 - 同时仍保持必备供应全部依赖到实例化的东西。

当然,最有意义的,如果有某种依存关系的逻辑分组的,因此该化合物不是任意聚集较多,而且最有意义的,如果有一个单一化合物依赖多个依赖 - 但参数块“模式”有存在了很长一段时间,而且大多数的,我已经看到已经相当随意。

就个人而言,虽然,我使用的方法/属性的制定者到指定的依赖关系,选项等骂人有助于描述是怎么回事的更多粉丝。 这是一个好主意,提供例如,这-IS-如何对设置它了片段,不过,并确保相关类做足够的错误检查。 你可能想用一个有限状态模型的建立。



Answer 11:

最近,我遇到了一个情况 ,我在一个类中有多个依赖,但只有一个依赖是必然要在每一个实现改变。 由于数据访问和错误日志的依赖性可能仅会被用于测试目的变了,我增加了对这些依赖可选参数 ,并在我的构造函数代码提供这些相关的默认实现。 通过这种方式,类保持其默认行为,除非类的消费者覆盖。

使用可选的参数只能在支持他们的框架,例如.NET 4来完成(对于C#和VB.NET,虽然VB.NET一直有它们)。 当然,你可以通过简单的使用,可以通过类的消费者被重新分配一个属性来完成类似的功能,但你没有得到通过具有分配给构造函数的参数的专用接口对象提供的不变性的优点。

所有这一切是说,如果你正在引进必须由每一位消费者提供一个新的依赖,你将不得不重构你的构造函数和所有的代码,消费者类。 我的上述建议,如果你有能够为目前所有的代码提供一个默认的实现奢侈品,但仍然提供在必要时覆盖默认实现的能力真才适用。



Answer 12:

这是一个古老的职位,但如果它是需要在未来也许这是任何使用:

https://github.com/omegamit6zeichen/prinject

我也有类似的想法,并与该框架上来。 它可能尚不完整,但它是一个框架的概念侧重于财产注入



Answer 13:

这取决于你想如何实现。 我更喜欢构造函数注入的地方,我觉得去到执行犯规经常改变的值。 例如:如果COMPNAY stragtegy与Oracle服务器的时候,我会配置我datsource值豆achiveing通过构造函数注入连接。 另外,如果我的应用程序是一个产品和机会,它可以连接到客户的任何一个分贝,我会实现这样的数据库配置,并通过setter注入多品牌实施。 我刚才已采取一个例子,但也有实现我上面提到的场景的更好的方法。



Answer 14:

构造函数注入并明确揭示的依赖性,使代码更易读,如果参数在构造函数中托运不易未处理的运行时错误,但它确实归结为个人的意见,并使用DI的越多,你会往往会来回晃动的一种方式或其他根据项目。 我个人有问题的代码气味像的参数一长串的构造,我觉得一个对象的消费者应该知道,为了仍要使用该对象的依赖关系,因此使得这种使用性能喷射的情况下。 我不喜欢酒店的注射的隐含性质,但我觉得它更优雅,导致清洁的前瞻性代码。 但在另一方面,构造函数注入确实提供了更高程度的封装,并在我的经验,我会尽量避免默认构造,因为它们可以对封装的数据完整性的不良影响,如果一个不小心。

通过构造函数或通过明智地根据您的具体方案属性中注射。 不要觉得你必须使用DI只是因为它似乎是必要的,它会阻止糟糕的设计和代码味道。 有时它不值得使用如果努力和复杂性远远大于好处的模式的努力。 把事情简单化。



文章来源: Dependency injection through constructors or property setters?