依赖反转原则|设计原则

简介: 依赖反转也称为依赖倒置,它的定义是十分抽象的。

前置知识

前言

本文带大家学习 依赖反转原则

依赖反转也称为依赖倒置,它的定义是十分抽象的。

首先我们看一下它的英文释义:

High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on details. Details depend on abstractions.

将上文翻译之后,其含义是这样子的:

高层模块不要依赖低层模块。高层模块和低层模块应该通过抽象来互相依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象

初看这个定义,会觉得很绕,啥是高层模块,啥是低层模块?怎么又通过抽象来相互依赖?等等的这些问题,让我们难以理解上文的释义

下文我们将对此进行介绍和举例,同时介绍与其相近的控制反转,以及依赖注入,相信阅读之后,你对依赖反转会有更深的理解

依赖反转

理解 依赖反转 的定义,首先我们回答一下几个问题。

  • 何为高层模块、低层模块?
    高层模块我们可以理解为调用方,而低层模块则理解为被调用方
  • 如何通过抽象来相互依赖?
    即调用者与被调用者之间无直接依赖关系,而是两者都遵从某种协议、某些抽象类、或是某些接口
  • 如何只由实现细节依赖抽象?
    这一点是符合抽象的定义的,抽象只负责顶层指导,而由对应的继承者来实现这些抽象

解释完上面的问题,我们会发现,这个依赖反转原则与“基于接口而非实现编程”有些类似。事实上,该原则的核心就是“基于接口而非实现编程”。依赖反转通俗来说就是,把高层依赖低层反转一下,变成高层底层都依赖抽象

但是,依赖倒置原则 在业务开发中并不常见,因为业务开发中 高层模块直接依赖低层模块 是极为常用且正常的。更多的是使用到其核心,“基于接口而非实现编程”。依赖倒置原则更侧重与指导框架的设计,例如我在 带你封装MVP架构(下) 一文中,就使用到了依赖倒置原则。

相关的依赖倒置举例如下

Tomcat

Tomcat 是运行 Java Web 应用程序的容器。我们编写的 Web 应用程序代码只需要部署在 Tomcat 容器下,便可以被 Tomcat 容器调用执行。按照之前的划分原则,Tomcat 就是高层模块,我们编写的 Web 应用程序代码就是低层模块。Tomcat 和应用程序代码之间并没有直接的依赖关系,两者都依赖同一个“抽象”,也就是 Servlet 规范。Servlet 规范不依赖具体的 Tomcat 容器和应用程序的实现细节,而 Tomcat 容器和应用程序依赖 Servlet 规范。

Room封装使用

数据库案例也符合依赖倒置原则,高层模块(业务层)不依赖于低层模块(SQLiteDao/RoomDao),而是依赖于抽象(IDao)——开闭原则设计

控制反转

控制反转 缩写为IOC(Inversion Of Control),简单解释其意思为:把控制权反转过来

具体是把控制权从谁手中反转过来呢?从程序员手中。那反转到谁那里呢,反转到代码框架那里。

这个概念的本意是,程序员在编写代码的时候,编写了设置了整个代码流程,此时控制权在程序员手中。

当对代码抽象框架化,代码拓展性提高,且最终由框架实现代码流程。程序员只输入少量代码启动代码流程,这个就是符合控制反转思想。

框架提供了一个可扩展的代码骨架,用来组装对象、管理整个执行流程。程序员利用框架进行开发的时候,只需要往预留的扩展点上,添加跟自己业务相关的代码,就可以利用框架来驱动整个程序流程的执行。

但是控制反转只是一种设计思想,具体的实现方式各式各样。前文 开闭原则 的demo中,其设计也是符合控制反转原则的,最终是由框架自行驱动程序。

对应的,LiveData 也是一种控制反转思想的变体,与 MVP 的由 P层 驱动 View 层一样,使用数据驱动 UI。

依赖注入

依赖注入 与控制反转不同的是,依赖注入是一种实现控制反转的具体方法

其意思为:把被依赖项通过参数等的形式,注入到类中

具体实现如下

public interface ImageGetter {
  void get(String imageUrl);
}
public class PictureStore {
  private ImageGetter imageGetter;
  public PictureStore(ImageGetter imageGetter) {
    this.imageGetter = imageGetter;
  }
  public void imageGet(String imageUrl) {
    this.imageGetter.get(imageUrl);
  }
}
// 从aliyun获取
public class AliyunGetter implements ImageGetter {
  @Override
  public void get(String imageUrl) {
    //....
  }
}
// 从Tencent云获取
public class TecentGetter implements ImageGetter {
  @Override
  public void get(String imageUrl) {
    //....
  }
}
复制代码
//使用图床类
ImageGetter imageGetter = new TecentGetter();
PictureStore pictureStore = new PictureStore(imageGetter);//依赖注入
pictureStore.imageGet("https://...");
复制代码

上述的demo就是实现了依赖注入,把被调用的类通过构造函数注入了对应的类中。对应的控制、代码流程已经反转到框架来实现,所以说,依赖注入实现了控制反转,且其为控制反转的一种重要实现方式。

但是我们也发现了,虽然说控制权反转给了框架,程序员只需做对应的拓展和启动。但是终究这个框架还是要我们自己来实现,当项目变大的时候,我们还是会容易出错的,所以后端开发中常使用 spring boot 这种控制反转容器。这类称之为,依赖注入的框架,在Android中,我们也有常用的依赖注入框架,帮助我们更好的做依赖注入。Dagger2 就是 Google 开发的一款依赖注入框架,大家可自行了解。

三者区别

依赖反转原则是一种设计原则,与控制反转类似,都是框架层面的设计指导。只不过两者作用的对象不同,一个是依赖方,一个是控制权。

而依赖注入则纯为一种实现控制反转的方法,是一种规定好的技巧形式。


相关文章
|
3月前
|
设计模式 算法 开发者
设计模式问题之最小知识原则(迪米特法则)对代码设计有何影响,如何解决
设计模式问题之最小知识原则(迪米特法则)对代码设计有何影响,如何解决
|
4月前
|
存储
业务系统架构实践问题之倒置依赖和非倒置依赖有什么区别
业务系统架构实践问题之倒置依赖和非倒置依赖有什么区别
|
6月前
|
Java 测试技术 开发者
循环依赖:解析软件设计的迷局
循环依赖:解析软件设计的迷局
|
设计模式 网络协议 测试技术
你的代码是否按照高内聚、低耦合的原则来设计的?
你的代码是否按照高内聚、低耦合的原则来设计的?
|
测试技术
软件设计原则-单一置原则讲解以及代码示例
单一职责原则(Single Responsibility Principle,SRP)是面向对象设计中的一个重要原则,提倡将一个类或模块只负责一个职责或功能。它最早由Robert C. Martin在其《敏捷软件开发:原则、模式与实践》一书中提出。 单一职责原则的核心思想是:一个类或模块应该只有一个引起它变化的原因。也就是说,每个类或模块都应该只有一个职责或功能,并且该职责或功能应该在该类或模块内部封装起来,而不是分散到多个类或模块中。
92 0
软件设计原则-合成复用原则讲解以及代码示例
合成复用原则(Composition/Aggregation Reuse Principle,CARP)是面向对象设计的一种重要原则,也被称为组合/聚合复用原则。它强调通过组合(Composition)或聚合(Aggregation)关系来达到代码复用的目的,而不是通过继承关系。
192 0
《软件架构之道》c#实现依赖反转
《软件架构之道》c#实现依赖反转
|
设计模式 测试技术 程序员
代码的简单设计五原则
代码的简单设计五原则
33087 1
|
设计模式 Oracle 关系型数据库
软件架构设计原则--合成复用原则
本专栏内容参考自:咕泡学院Tom老师的《Spring5核心原理与30个类手写实战》,仅作个人学习记录使用,如有侵权,联系速删
|
设计模式
设计原则(六):DIP 依赖反转原则
设计原则(六):DIP 依赖反转原则
152 0