1.1 概述
依赖倒置原则(Dependence Inversion Principle,DIP)是 Object Mentor 公司总裁罗伯特·马丁(Robert C.Martin)于 1996 年在 C++ Report 上发表的文章。依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)。其核心思想是:要面向接口编程,不要面向实现编程。
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。
1.2 优点
① 依赖倒置原则可以降低类间的耦合性。
② 依赖倒置原则可以提高系统的稳定性。
③ 依赖倒置原则可以减少并行开发引起的风险。
④ 依赖倒置原则可以提高代码的可读性和可维护性。
1.3 案例
如下图所示,Computer 类中 cpu 方法参数类型是 AMD,这样有没有问题呢?运行是一点问题都没有的,CPU 用 AMD 品牌的能有什么问题嘛。但是我们想换成 Intel 的 CPU 的时候就出现了问题,Computer 与 AMD 绑定了,如果 AMD 倒闭了岂不是电脑厂家要收到很大的影响。
为了避免上述情况的发生 Computer 决定使用一个高层接口,这样不论是 AMD 还是 Inter 都能够接入。以上这种行为就体现了依赖倒置原则。
开发时,为了使得常用代码可以复用,一般都会把这些常用代码写成许许多多函数的程序库,这样我们在做新项目时,去调用这些低层的函数就可以了。比如我们做的项目大多要访问数据库,所以我们就把访问数据库的代码写成了 Utils,每次做新项目时就去调用这些 Utils。这也就叫做高层模块依赖低层模块。在一个新项目中,发现业务逻辑的高层模块都是一样的,但客户却希望使用不同的数据库或存储信息方式,这时就出现麻烦了。我们希望能再次利用这些高层模块,但高层模块都是与低层的访问数据库绑定在一起的,没办法复用这些高层模块,这就非常蛋疼。
如果不管高层模块还是低层模块,它们都依赖于抽象,具体一点就是接口或抽象类,只要接口是稳定的,那么任何一个的更改都不用担心其他受到影响,这就使得无论高层模块还是低层模块都可以很容易地被复用。就好比 JDBC 不论使用 MySQL 还是 Oracle 都没有影响。为什么依赖于抽象就不会收到影响就需要谈到“里氏替换原则”。
简单提一下依赖传递的三种方式:第一种,构造方法传递;第二种,setter 方法传递;第三种,参数传递。