使用DI / IoC是否应该删除所有出现的“ new”关键字?


21

使用依赖注入和控制反转容器是否应该从代码中删除所有出现的“ new”关键字?

换句话说,是否应该将每个对象/依赖项(无论多么简单或短暂)都“注册”到IoC容器中,并注入到需要使用它们的方法/类中?

如果不是,您如何在new关键字IoC容器中注册依赖项/对象与通过关键字“内联”创建的具体引用之间划清界限?


我曾经有过相同的想法,即“'new'是一个4个字母的单词吗?”。
迈克尔·复活节

Answers:


27

避免教条。做正确的事。

我更喜欢对没有行为的数据结构使用“ new”。

如果该类确实有行为,那么我将研究该行为的范围。如果它是无状态的并且没有依赖项,那么我倾向于“新”。我仅在需要向有状态资源(例如数据库或文件)或具有此类资源的其他类添加依赖项时才开始对DI进行重构。


15
为“避免教条” +1。在不了解正在发生的事情或应该在哪里正确使用它的情况下,太容易陷入仅跟随动作的陷阱中了。
韦恩·莫利纳

@Alex我喜欢这个。一个非常实用的方法。有趣的是,我要在问题中添加一些代码,new在我自己的代码中显示“ ed依赖性”,这提示了我的问题。这是一个简单的类,本身没有功能或“行为”,只有简单的属性。
CraigTP

11

我的书中,我对稳定依赖项不稳定依赖项进行了区分。将DI与易失性依赖关系一起使用是最重要的,但是通常您也可以通过抽象和注入稳定依赖关系来实现更宽松的耦合。

请记住,DI的应用程序不应依赖DI容器。在使用穷人DI的情况下,不会new删除任何关键字-它们只会移至“ 合成根目录”

实际上,有些人更喜欢穷人的DI,而不是DI容器。维护成本可能会更高,但是您可以获得编译时的安全性。正如我最近听到的Dan North所说:“ new是新的new” :)

这意味着它不是仅用一堆嵌套new语句来代替用DI容器实现“合成根”,而是简单地代替。


马克,在我的Twitter评论中扩大一点,程序员是解决概念性白板问题的合适地方,这些问题不会解决实现中的特定错误。
亚当李尔

3
Stack Overflow在依赖项注入标签中有2000多个问题,其中很多都与此类似。程序员在同一标签中有23个问题。根据这些数字,开发人员应该在哪里获得这样的问题的最大机会?
Mark Seemann

1
这些问题很多都早于程序员。创建此站点的目的是解决SO方面的概念性问题,并为他们提供专用的家。而且我们还在成长。这项工作仍在进行中,但理想情况下,不涉及特定实现问题的问题将在此处进行移植。同时,我们会尽力而为。
亚当李尔

3

“ new”不是禁止的关键字。我的个人规则:

所有“服务”(我将服务称为旨在提供一种或多种与一件事情有关的方法的类;例如:访问数据库,检索/更新与给定域有关的数据)已注册在IOC容器中。无需任何类来决定如何获取需要使用的给定服务的实现。因此,每当需要使用现有服务时,都应配置您的类和IOC容器以将其提供给您。想象一下,您不知道实现的工作原理,它可能是Web服务,您不在乎。

当我需要启用所有默认属性时,将使用“ new”关键字或使用IOC注册的工厂来创建所有bean或模型。实用程序类也有特殊情况,它仅包含静态方法(例如:数学实用程序服务)。如果它们是完全独立的,并且不需要任何数据库连接或其他IOC注册的服务,则可以将它们放在IOC之外,并将其静态调用。但是,如果一个此类需要使用现有的IOC注册服务,则将其更改为单例类并在IOC中注册。


2

我只想添加到earler提出的现有答案中,就new可以创建纯值对象(即仅具有属性/获取器/设置器)的对象。有关更多详细信息,请参见Google测试博客


+1的链接。9点在博客中回答了这个问题,并提供之间应该怎样,不应该是一个务实的区别new“编
CraigTP

1

显然取决于您使用的语言。如果您的语言强迫您使用对象来表示实际对象和记录(值对象,结构),那么答案很可能不是。

纯粹说“真实”对象,显式创建实例没有错。但是,您必须记住的是,所有课程都应遵循单一责任原则。选择类所依赖的服务的实现者不是类的责任。但是,有些班级对此负有很大责任,即提供某些服务的实现者。IoC可能就是此类。实际上,任何类型的工厂都属于此类。

总结一下:只有这样的类才应直接实例化对象,由谁负责选择要实例化的类。
您可能会发现这些条件很有帮助:http : //en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Creator


1

一个字:不。

更多的话:依赖注入就是这样。通过这种方法,您可以从另一个来源介绍另一个对象所依赖的资源,但不应了解其复杂的细节。使用DI并不意味着程序中的NOTHING应该不知道如何创建任何其他对象。实际上,我认为非平凡的程序完全避免使用“ new”关键字(或基于反射的替代方法)是不可行的。但是,DI确实意味着那些不应该知道如何创建需要大量依赖关系的复杂对象的对象将这些对象紧密地耦合到另一个对象,而不应该具有所有这些紧密耦合的知识。

我将研究O / O软件设计的两个主要理论,即GRASP和SOLID。GRASP会告诉您研究对象的目的,并问自己:“该对象是否应负责创建其他类型的新对象?这是该对象的“工作描述”的一部分吗?” SOLID进一步迈进了一步:“ S”代表“单一责任原则”,该原则明确声明一个对象应该有一个工作,并且它应该是程序中唯一可以完成该特定工作的对象。

因此,GRASP通常会鼓励您浏览创建这些新对象的现有类,并在创建所需对象的同时,在保持所需“凝聚力”的同时找到创建该对象的任务与该对象已经完成的工作相适应的类。SOLID会告诉您凝聚力是关键;创建这些对象的任务应该交给应该注入您的类的工厂。我想您会发现,随着程序复杂度的不断提高,遵循这两种方法中的任何一种,并且愿意进行重构,都将导致非常类似的体系结构。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.