在我的上一个大型项目中,我非常大量地使用了依赖注入。我一开始使用构造函数注入,但是即使有两到三个依赖项,也会产生非常难看的代码。
public MyClass(
IDependency1 dependency1,
IDependency2 dependency2
IDependency3 dependency3)我不喜欢财产注入。有些人说这意味着一种“可选的”依赖。我认为它们的意思是会有一个默认的依赖项(生产类),但是在测试期间可以用一个模拟对象来替换它。很多时候,我的依赖项也有依赖项,所以除非我使用了单例或其他东西,否则我无法提供默认值。属性注入的问题是,我更喜欢完全初始化的对象,并且不希望意外地忘记在测试期间模拟依赖项。
所以我找到了一个折中方案。我创建了一个“参数对象”,它具有所有依赖项的属性。我把这些交给了我的建筑工人。这样做的好处是使我的代码保持了一些更干净的功能,并且如果没有接触到这些依赖项,我可以在测试期间忽略它们。
根据反馈,我觉得这是个坏主意。它是构造函数注入或参数注入-不允许妥协。后来,我意识到这些参数对象有时成为它们自己的类(或一组类)。
那时我发现了一个有趣的模式。许多业务对象依赖于其他业务对象,这些业务对象有它们自己的依赖关系。最后,我得到了一个有趣的数据结构,类似于一个链接列表。

这个数据结构可能会变得相当复杂,取决于交互类的数量。在大多数情况下,结构更接近于n叉树.每个参数对象可以链接到任意数量的其他对象(包括其他业务对象)。业务对象是树的节点,参数对象类似于连接它们的边缘。

我认为,如果不使用声明性依赖注入框架将所有这些对象连接在一起,就会让人感到麻木。在我的代码中,我使用的依赖注入框架深入到了8个层次,在最坏的情况下,从下到上构建依赖关系。
参数对象通常只公开依赖项。在一些情况下,我会将它们隐藏在友好函数调用的后面,并使它们成为自己的业务对象(通常会产生另一个参数对象)。我不得不提醒自己,参数对象只存在于构造函数中,因为我不想在构造函数中构造依赖项(或者将它们传递给构造函数)。只有当我开始重复自己的话时,创建新的业务对象才有意义。即使如此,我还是以参数对象的爆炸而告终。
我读了很多书,解释说这种情况永远不会发生。类应该只有很少的依赖项。这表明我的课“做得太多了”。但在大多数情况下,业务对象使用来自多个数据库表(存储库)、配置设置、服务等的数据来进行计算。这通常发生在实现一系列组成工作单元的步骤时。当一个任务需要N件事情时,你能做的最好的事情就是将N件事情推到其他类或在调用堆栈上。一个有6个依赖项的类,还是每个有两个依赖项的3个类更好还是更差?
我希望得到一些关于这种依赖注入方法的反馈--在它与构建业务层的关系方面。
发布于 2013-03-21 08:00:55
IMHO通过构造函数创建“完整”类一直很有吸引力,但是setter注入需要一个no-arg构造函数,允许预条件(例如断言)是保证DI容器上下文中“完整性”的合理选择。
对我来说,这是在增加复杂性和实现一个简单、务实的解决方案之间的权衡。简单永远都是赢家。
发布于 2013-02-27 23:13:08
老实说,中间的“参数”类在这里似乎有点过于工程化了。您正在引入加深对象图并实际上隐藏依赖项的代码。
在使用容器时,您可以设置您的环境,以便容器实际创建任何您需要的对象以及它的所有依赖项。我通常所做的是设置基础结构或框架,以便每当我在实际的应用程序代码中时,我的所有依赖项都已经设置好了。我将以同样的方式设置我的测试环境,这样我就不会忘记依赖。
当使用像Asp.Net MVC这样的框架时,这意味着设置框架,以便每个控制器实际上由容器解析。这里的控制器是应用程序的入口点。由于控制器将依赖于各种存储库和服务,容器也将解析这些和它们的依赖关系,不管图形有多深。
这意味着,如果我不盲目地实例化服务或存储库,那么无论依赖项是通过构造函数还是通过setter设置,我都会有完全可以完成其工作的对象。
通过一些规划,应用程序层(控制器/视图/视图)和业务层(存储库/服务)可以驻留在一个基础结构中,您不必使用new操作符实例化服务,甚至不必使用容器来解决它(这更好,但如果不小心使用,可能会导致问题,在容器本身中引入不必要的依赖)。
关于setter与构造函数注入,我不认为setter注入意味着可选的依赖项。它们和其他类一样是依赖关系,当您有一个类的层次结构时,它们非常有用,在这些类中,构造函数注入意味着通过多个构造函数级别拖动参数,直到最终在某个基类中设置依赖项。当然,他们也有他们的权衡,具体来说,使用setter注入时,您必须小心构造器逻辑,在设置对象之外,应将构造逻辑保持在最低限度。
https://softwareengineering.stackexchange.com/questions/188644
复制相似问题