tl;dr - 构造函数注入是做DI的最佳方式
后者是正确的,这并不是因为Spring或任何依赖注入容器,而是面向对象的类设计原则。
详
应设计一个类型,以便您只能从该类型创建处于有效状态的实例。为此,该类型的所有必需依赖项都需要是构造函数参数。这意味着,可以检查这些依赖关系,将其分配给最终字段以提高不可变性。除此之外,在处理代码时,对于该实例的调用方(或创建者)来说,它必须提供哪些依赖项(通过浏览API文档或在IDE中使用代码完成)立即显而易见。null
所有这些都是现场注入不可能实现的。你不会从外部看到依赖关系,你需要一些黑魔法来注入依赖关系,你永远无法确定它们不是,除非你盲目地信任容器。null
最后但并非最不重要的方面是,使用字段注入,向类中添加大量依赖项的痛苦较小,这本身就是一个设计问题。对于构造函数来说,这在很久以前变得更加痛苦,这是一件好事,因为它告诉你一些关于你的类设计的事情:类有太多的责任。无需首先计算它的指标,当您尝试扩展它时,您会感觉到它。
器皿
人们经常争辩说,这只是学术上的胡说八道,因为你无论如何都可以依靠容器。以下是我对此的看法:
仅仅因为容器存在,并不意味着你必须抛弃所有基本的面向对象设计原则,不是吗?即使存在止汗剂,你仍然会洗澡,对吧?
即使是设计用于容器的类型,也将手动使用:在单元测试中。如果不编写单元测试...好吧,那是另一个话题了。
-
一个附加构造函数的所谓冗长性(“我可以通过一行字段注入来实现同样的事情!”- “不,你不能。你实际上从编写一行代码中得到更多的东西。可以通过龙目岛之类的东西来缓解。注入Spring和Lombok的构造函数组件如下所示:
@Component
@RequiredArgsConstructor
class MyComponent implements MyComponentInterface {
private final @NonNull MyDependency dependency;
…
}
龙目岛将负责生成一个构造函数,为每个最终字段获取一个参数,并在分配之前检查给定的参数。因此,您可以有效地获得现场注入的简洁性和构造函数注入的设计优势。null
结语
我最近与一些非Java人员进行了讨论,我对使用术语“注入”来表示构造函数DI感到非常困惑。实际上,他们认为 - 这有很多道理 - 通过构造函数传递依赖关系根本不是注入,因为这是将对象传递给其他对象的最自然的方式(与任何类型的注入形成鲜明对比)。
也许我们应该为这种风格创造一个不同的术语?也许是依赖喂养?
资源