本篇文章来自对 Nikola Malovic 博客文章 《Inversion Of Control, Single Responsibility Principle and Nikola’s laws of dependency injection》的翻译和改编。
关于控制反转(Inversion Of Control)的使用在社区中有很多讨论,如何更好的实现单一职责原则 (Single Responsibility Principle) ,更合理的利用依赖注入 (Depencency Injection) 一直是讨论的重点,本篇文章将介绍 Nikola Malovic 提出的关于使用 IoC 的 5 项法则。
依赖注入所遇到的问题:
- 如何避免将那些我们并不感兴趣的通用依赖项注入到每个类中?
- 如何处理那些有可能会用到,但是实例化过程特别昂贵的依赖项?
- 如何为我们的类构造对象图谱,而且要考虑到每个依赖项均有其自身的依赖项?
Nikola 的 5 项依赖注入法则
采用 DDD 设计原则,可以保持设计的整洁,代码可维护性更高。通常,实体类不应该依赖诸如基础设施服务类等。
Nikola 依赖注入法则 1 :仅在 IoC 容器中存储服务类,不要存储实体类(Entities)。
如果所设计的类在构造函数中注入了过多的依赖项,则可以考虑是否违背了 SRP (Single Responsibility Principle) 原则 和 SOC (Separation of Concerns) 原则。而通常这种类将可以被分解为多个内聚的类,而每个分解出的类将包含更少的依赖项。
Nikola 依赖注入法则 2 :任何包含超过 3 个依赖项的类都应该被怀疑违背了单一职责原则(SRP)。
通常,并不建议使用属性注入来代替构造函数注入,尽管属性注入可以移除哪些构造函数杂音。但事实上,真实直接的经验表明,属性注入是比构造函数注入更差的选择。这是因为采用属性注入方式,导致依赖项注入的不透明性。
Nikola 依赖注入法则 3 :类的每个依赖项均需要在类的构造函数中显示的注入。
对于从 IoC 容器构造的类实例来说,我们应该尽可能的保持构造函数的轻量,并仅定义类自身的依赖项。任何类的初始化或者部分实现都不应该由构造函数触发。取而代之的是在 IoC 容器构造类实例完毕后,显示的调用指定的类成员函数来实现。
Nikola 依赖注入法则 4 :类的每个构造函数中除了接受其依赖项集合的注入,不能包含任何其他实现。
通常,建议将所有 IoC 容器的注册映射过程集中在一个 Bootstrapper 中来处理,Bootstrapper 可以使用 Builder 模式进行构造。Bootstrapper 可以在应用程序的启动阶段进行初始化,构造所有依赖项的映射。而其他代码不应该意识到 IoC 容器的存在。
Nikola 依赖注入法则 5 :IoC 容器应该被显示的应用在 Bootstrapper 中。任何启用 IoC 的代码(包括单元测试代码)都应该完全不知道 IoC 容器的存在。