依赖反转原则|设计原则

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

前置知识

前言

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

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

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

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 开发的一款依赖注入框架,大家可自行了解。

三者区别

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

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


目录
打赏
0
0
0
0
97
分享
相关文章
|
9月前
|
详解Task 和 ValueTask 的使用区别
详解Task 和 ValueTask 的使用区别
174 0
Java一分钟之-Spring Integration:企业级集成
【6月更文挑战第11天】Spring Integration是Spring框架的一部分,用于简化企业应用的集成,基于EIP设计,采用消息传递连接不同服务。核心概念包括通道(Channel)、端点(Endpoint)和适配器(Adapter)。常见问题涉及过度设计、消息丢失与重复处理、性能瓶颈。解决策略包括遵循YAGNI原则、使用幂等性和事务管理、优化线程配置。通过添加依赖并创建简单消息处理链,可以开始使用Spring Integration。注意实践中要关注消息可靠性、系统性能,逐步探索高级特性以提升集成解决方案的质量和可维护性。
250 3
Java一分钟之-Spring Integration:企业级集成
探索Java中的Lambda表达式
本文将深入探讨Java 8引入的Lambda表达式,这一特性极大地简化了代码编写,提高了程序的可读性。通过实例分析,我们将了解Lambda表达式的基本概念、使用场景以及如何优雅地重构传统代码。文章不仅适合初学者,也能帮助有经验的开发者加深对Lambda表达式的理解。
如何实现Springboot+camunda+mysql的集成
【7月更文挑战第2天】集成Spring Boot、Camunda和MySQL的简要步骤: 1. 初始化Spring Boot项目,添加Camunda和MySQL驱动依赖。 2. 配置`application.properties`,包括数据库URL、用户名和密码。 3. 设置Camunda引擎属性,指定数据源。 4. 引入流程定义文件(如`.bpmn`)。 5. 创建服务处理流程操作,创建控制器接收请求。 6. Camunda自动在数据库创建表结构。 7. 启动应用,测试流程启动,如通过服务和控制器开始流程实例。 示例代码包括服务类启动流程实例及控制器接口。实际集成需按业务需求调整。
704 4
优化后端性能:提升Web应用响应速度的关键策略
在当今数字化时代,Web应用的性能对于用户体验至关重要。本文探讨了如何通过优化后端架构和技术手段,提升Web应用的响应速度。从数据库优化、缓存机制到异步处理等多个方面进行了深入分析,并提出了一系列实用的优化策略,以帮助开发者更好地应对日益增长的用户访问量和复杂的业务需求。
690 28
【完全复现】基于改进粒子群算法的微电网多目标优化调度
该文档描述了一个使用改进粒子群算法实现的微电网多目标优化调度的Matlab程序。该模型旨在最小化运行成本和环境保护成本,将多目标问题通过权值转换为单目标问题解决。程序中定义了决策变量,如柴油发电机、微型燃气轮机、联络线和储能的输出,并使用全局变量处理电负荷、风力和光伏功率等数据。算法参数包括最大迭代次数和种群大小。代码调用了`PSOFUN`函数来执行优化计算,并展示了优化结果的图表。
ZooKeeper【基础 01】简介+设计目标+核心概念+ZAB协议+典型应用场景
【4月更文挑战第10天】ZooKeeper【基础 01】简介+设计目标+核心概念+ZAB协议+典型应用场景
160 1
探索ERP系统的实施流程与方法论
探索ERP系统的实施流程与方法论
1599 2
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问