依赖倒置原则是什么?

依赖倒置原则(Dependency Inversion Principle)的目的在于软件模块的解耦,它的主旨是高层次的类不应该依赖于低层次的类,它们应该都依赖于抽象接口。抽象接口不可依赖于具体实现,而是具体实现依赖于抽象接口。
通常在设计软件时,我们是可以辨别出不同层次的类。比如:

  • 低层次的类实现一些基础操作,例如磁盘读写、传输网络数据和操作数据库等。
  • 高层次的类包含复杂的业务逻辑以指导低层次的类执行特定的操作。

有时候人们会先设计低层次的类,然后才会开发高层次的类。当我们在一个新系统上开发原型产品时,这种情况是很常见的。如果低层次的东西还没有实现或不确定,我们就难以确定高层次的类能实现哪些功能,采用这种方式会让业务逻辑代码更易于依赖低层次的原语类。
依赖倒置原则建议改变直接依赖的方式:

  1. 在高层次的类中应该使用业务术语并以接口的形式来描述它所依赖的低层次类的操作。例如,业务逻辑应该调用名为 open­Report­(file) 的方法,而不是 openFile(f)readBytes(n)closeFile(f) 等一系列方法。以业务术语描述的接口就可以被视为是高层次的。
  2. 基于这样的接口来创建高层次的类,而不是基于低层次的具体类。
  3. 一旦低层次的具体类实现了这些接口,它们将依赖于业务逻辑层,从而倒置了原来的依赖关系。

依赖倒置原则通常和开闭原则共同发挥作用:你无需修改已有的类就可以用不同的业务逻辑类来扩展低层次的类。

案例

依赖倒置原则有点难以理解,我们还是用一个简单的案例来帮助我们理解它。假设现在有一个基于 MySQL 数据库的财务管理系统,我们定义了一个 BudgetReport 类来维护预算报表,并且它使用了数据库类 My­SQLDatabase 来读取和保存报表数据。
image.png
我们的财务软件运行得很好,深受客户们的欢迎。但随着业务的发展和需求的变化,关系型数据库 MySQL 逐渐难以支撑部分客户对预算报表的处理。我们决定对系统进行升级,使用 MongoDB 来存储报表数据,以满足这部分客户的需求。但是,BudgetReport 类直接使用了 My­SQLDatabase 类,直接修改 My­SQLDatabase 类就会影响到 BudgetReport 类,而且万一以后需要再次对数据库进行升级,我们仍然会遇到同样的困境!
为了解决这个问题,我们可以创建一个描述数据库操作的高层次接口,并让报表类使用该接口来代替具体的低层次类,这样我们就可以通过扩展这个低层次的接口来实现业务逻辑。
image.png

参考资料

以下是本文参考的资料: