设计原则(六):DIP 依赖反转原则

简介: 设计原则(六):DIP 依赖反转原则

背景介绍


这是我的《架构整洁之道》系列的第十篇,这一篇我们将一起学习 DIP 依赖反转原则~


高层策略性的代码不应该依赖实现底层细节的代码,恰恰相反,那些实现底层细节的代码应该依赖、高层策略性的代码。


《架构整洁之道》系列:


DIP 依赖反转原则


依赖、反转原则(DIP)主要想告诉我们的是,如果想要设计一个灵活的系统,在源代码层次的依赖、关系中就应该多引用抽象类型,而非具体实现。


显而易见,把这条设计原则当成金科玉律来加以严格执行是不现实的,因为软件系统在实际构造中不可避免地需要依赖到一些具体实现。


我们主要应该关注的是软件系统内部那些会经常变动的具体实现模块,这些模块是不停开发的,也就会经常出现变更。


稳定的抽象层


我们每次修改抽象接口的时候,一定也会去修改对应的具体实现。但反过来,当我们修改具体实现时,却很少需要去修改相应的抽象接口。所以我们可以认为接口比实现更稳定


也就是说,如果想要在软件架构设计上边求稳定,就必须多使用稳定的抽象接口,少依赖多变的具体实现:


  • 应在代码中多使用抽象接口,尽量避免使用那些多变的具体实现类


对此,我们通常会选择用抽象工厂(abstractfactory)这个设计模式


  • 不要在具体实现类上创建衍生类
  • 不要覆盖(override)包含具体实现的函数
  • 应避免在代码中写入与任何具体实现相关的名字,或者是其他容易变动的事物的名字


工厂模式


如果想要遵守上述编码守则,我们就必须要对那些易变对象的创建过程做一些特殊处理。在大部分面向对象编程语言中,人们都会选择用抽象工厂模式来解决这个源代码依赖的问题。


如下图,Application 类是通过 Service 接口来使用 ConcreteImpl 类的。 然而,Application 类还是必须要构造 ConcreteImpl 类实例。于是,为了避免在源代码层次上引入对 ConcreteImpl 类具体实现的依赖,我们现在让 Application 类去调用 ServiceFactory 接口的 makeSvc 方法。这个方法就由 ServiceFactoryImpl 类来具体提供,它是 ServiceFactory 的一个衍生类。该方法的具体实现就是初始化一个 ConcreteImpl 类的实例,并且将其以 Service 类型返回。


网络异常,图片无法展示
|


上面的例子中,具体实现组件的内部仅有一条依赖关系,这条关系其实是违反 DIP 的。这种情况很常见,我们在软件系统中并不可能完全消除违反 DIP 的情况。通常只需要把它们集中于少部分的具体实现组件中,将其与系统的其他部分隔离即可。

绝大部分系统中都至少存在一个具体实现组件一一我们一般称之为 main 组件, 因为它们通常是 main 函数所在之处。上面的例子中,main 函数应该负责创建 ServiceFactoryimpl 实例,并将其赋值给类型为 ServiceFactory 的全局变量,以便让 Application 类通过这个全局变量来进行相关调用。


// TODO:我没有完全理解上述例子,抽象工厂模式单独出一篇文章


中间的那条曲线代表了软件架构中的抽象层与具体实现层的边界。在这里,所有跨越这条边界源代码级别的依赖关系都应该是单向的,即具体实现层依赖抽象层


上图中的这条曲线将整个系统划分为两部分组件:抽象接口与其具体实现


  • 抽象接口组件:包含了应用的所有高阶业务规则
  • 具体实现组件:包括了所有这些业务规则所需要做的具体操作及其相关的细节信息

DIP 被称为依赖反转原则的原因控制流跨越架构边界的方向源代码依赖关系跨越该边界的方向正好相反,源代码依赖方向永远是控制流方向的反转


结束语


网络异常,图片无法展示
|


在系统架构图中,DIP 通常是最显而易见的组织原则。我们在后续会把工厂模式章节图片中的那条曲线称为架构边界,而跨越边界的、朝向抽象层的单向依赖关系则会成为一个设计守则一一依赖守则


最后


✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

少年向来不识天高地厚
放眼处皆自负才高八斗
虽是自命风流
倒也坦诚无忧
我爱这样的少年
谦和而狂妄
骄傲又坦然☀️

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

相关文章
|
Unix 网络安全 iOS开发
Mac 电脑如何安装Wireshark?
Mac 电脑如何安装Wireshark?
1375 0
Mac 电脑如何安装Wireshark?
|
运维 关系型数据库 MySQL
|
11月前
|
存储 关系型数据库 MySQL
mysql怎么查询longblob类型数据的大小
通过本文的介绍,希望您能深入理解如何查询MySQL中 `LONG BLOB`类型数据的大小,并结合优化技术提升查询性能,以满足实际业务需求。
462 6
|
存储 NoSQL 数据库
知识图谱之图数据库如何选型:知识图谱存储与图数据库总结、主流图数据库对比(JanusGraph、HugeGraph、Neo4j、Dgraph、NebulaGraph、Tugrapg)
知识图谱之图数据库如何选型:知识图谱存储与图数据库总结、主流图数据库对比(JanusGraph、HugeGraph、Neo4j、Dgraph、NebulaGraph、Tugrapg)
知识图谱之图数据库如何选型:知识图谱存储与图数据库总结、主流图数据库对比(JanusGraph、HugeGraph、Neo4j、Dgraph、NebulaGraph、Tugrapg)
|
数据挖掘 物联网 API
API接口在各个领域的发挥着什么样的作用呢
API接口在电商、金融、医疗、物联网、媒体和游戏等领域发挥重要作用。从商品管理、支付集成、用户管理,到金融风控、医疗数据共享、智能交通,再到内容整合、数据分析和游戏数据交互,API助力各行业实现高效协同与创新。
|
移动开发 编解码 数据可视化
低代码可视化-uniapp SliderRange区间组件-代码生成器
SliderRange区间组件是一种用户界面元素,允许用户通过拖动滑块选择数值范围。组件支持微信小程序、H5和App,具有高度可定制性、响应式设计和多种事件处理功能。适用于价格筛选、音量调节等场景。代码实现包括滑动区域、滑块、事件处理等部分,支持可视化配置步长、颜色等属性。使用时需注意选择合适步长、提供清晰标签和考虑无障碍设计。
375 0
|
JSON 自然语言处理 数据处理
数据标注工具 Label-Studio
数据标注工具 Label-Studio
4600 0
|
机器学习/深度学习 数据采集 算法
数据挖掘实战 —— 抖音用户浏览行为数据分析与挖掘(二)
数据挖掘实战 —— 抖音用户浏览行为数据分析与挖掘(二)
880 1
|
SQL 存储 分布式计算
【深入MaxCompute】人力家:用MaxCompute 事务表2.0主键模型去重数据持续降本增效
MaxCompute新增Transaction Table2.0(下文简称事务表2.0)表类型在2023年6月27日开始邀测,支持基于事务表2.0实现近实时的增全量一体的数据存储、计算解决方案。
992 1
|
开发框架 前端开发 JavaScript
疯狂吐槽 MAUI 以及 MAUI 入坑知识点
窗口 窗口管理 如何限制一次只能打开一个程序 MAUI 程序安装模式 为 MAUI Blazor 设置语言 坑 ① 坑 ② 坑 ③ 配置 MAUI 项目使用管理员权限启动 问题背景 定制编译过程 MAUI 实现前后端分离开发 背景 先搞前端 创建 MAUI Blazor 项目 C# 自动化生成证书、本地安装证书、解决信任证书问题 背景 写代码 在 ASP.NET Core 中使用
2658 0