【愚公系列】2022 年 06 月 面向对象设计原则 (四)- 依赖倒置原则
前言
常用的面向对象设计原则有七个,这七大设计原则都是以可维护性和可复用性为基础的,这些原则并不是孤立存在的,它们相互依赖相互补充,遵循这些设计原则可以有效地提高系统的复用性,同时提高系统的可维护性。
一、依赖倒置原则(Dependence Inversion Principle DIP )
<font color=#999AAA >高层模块不应该依赖低层模块,他们都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
简单的定义为:面向接口(抽象)编程,不要面向实现编程。
什么是高层模块?简单地说,就是封装的层级高,我们就认为其是高层模块。Customer 类是一个客户类,该客户包含 UnlockPhone 解锁手机方法,该方法需要传递一个 XiaoMiPhone 的手机类以便解锁手机,那么 Customer 类就是高层模块,XiaoMiPhone 类就是低层模块。
什么是细节?细节就是实例方法,是一个完整的、足够小的逻辑单元,是一段包含代码的子程序。什么是抽象?在 C#中,抽象就是抽象类(准确地说,应该是抽象类中的抽象方法,因为抽象类中可以包含实例方法)或接口,他们都无法被直接实例化,只能通过抽象类的子类、接口的实现类或工厂方法提供实例(容器也可以提供实例,但其本质上仍是工厂)。实际上抽象根本无法依赖细节,因为 C#语法规定,抽象方法和接口无法包含实现,即不可能包含细节,这就是“抽象不应该依赖细节”。那么什么是“细节应该依赖抽象”呢?细节应该依赖抽象可以认为是里氏替换原则的升级版,它要求尽可能的使用抽象基类或接口作为方法的参数。
二、使用步骤
示例
通过上面的代码我们可以明显看到,高层模块 Customer 类严重依赖低层模块 XiaoMiPhone 类,因为 UnlockPhone 方法需要一个 XiaoMiPhone 类的参数,这种强依赖关系导致的一个后果是,无论修改了 Customer 类还是 XiaoMiPhone 类,都无法保证调用方一定可以正确运行,我们需要对这 2 个类做完整的回归测试。另外一个问题是,有一天我们想解锁 IphoneX,将要对以上代码进行大规模的修改,这显然违背了开闭原则。以下给出一个解决方案以供参考:
首先通过 IMobilePhone 建立契约,提供 Unlock 方法,XiaoMiPhone 和 ApplePhoneX 类实现 IMobilePhone 接口,高层模块 Customer 不再依赖某一确定的手机类,而是依赖于 IMobilePhone 接口,即高层模块依赖于抽象。那么低层模块呢?本例中的低层模块为具体的手机类,它并不依赖任何模块,高、低层模块是相对的概念,实际开发过程中低层模块 ApplePhoneX 可能依赖于其它更低层的模块以便提供更多的功能,对于这个更低层的模块,ApplePhoneX 变成了它的高层模块,毕竟“生命不息,依赖不止”。
通过上面的分析我们不难发现,本来高层模块依赖低层模块,经过代码改造后,变成了它们都依赖于抽象,即依赖发生了转移,这就是所谓的“依赖倒置原则”。实现依赖倒置的方式称为依赖注入(Dependency Injection),常见的依赖注入方式有 3 种,构造注入,设值注入、接口注入。
注:另外还有一种服务定位器注入的方式,这将在以后 Asp.Net 的相关文章中为大家详细介绍。
构造注入:
设值注入:
接口注入:
综上所述,我们不难得到结论,注入是手段,依赖倒置是目的。<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">
总结
依赖倒置原则的主要作用如下。
依赖倒置原则可以降低类间的耦合性。
依赖倒置原则可以提高系统的稳定性。
依赖倒置原则可以减少并行开发引起的风险。
依赖倒置原则可以提高代码的可读性和可维护性。
版权声明: 本文为 InfoQ 作者【愚公搬代码】的原创文章。
原文链接:【http://xie.infoq.cn/article/9e0fb6baef5815960aeca7c13】。文章转载请联系作者。
评论