设计模式六大原则之:依赖倒置原则
1. 依赖倒置原则简介
依赖倒置原则(Dependency Inversion Principle, DIP) 是面向对象设计的核心原则之一,由罗伯特·马丁(Robert C. Martin)提出,旨在降低类间的依赖度,使之更易于维护和扩展。该原则主张高层模块不应该依赖于底层模块,两者都应依赖于抽象接口。
依赖倒置原则强调的是通过引入接口和抽象类来代替直接的类依赖,使得系统设计更灵活,组件间的耦合度更低。这有助于提升系统的整体复用性和扩展性。
它要求程序在设计和实现时应该依赖于抽象接口,而不是直接依赖于具体的实现。依赖倒置原则的实现关键在于对抽象进行编程,而非对实现进行编程,从而使得软件设计更加灵活和可扩展。
2. 依赖倒置原则核心思想
依赖倒置原则包含以下三层含义:
-
高层模块不应该依赖低层模块:这里的“高层”和“低层”指的是模块之间的依赖关系。按照依赖倒置原则,无论是高层模块还是低层模块,都应该依赖于抽象,而不是直接依赖于具体的实现。这样,当底层模块发生变化时,高层模块不需要进行修改,从而提高了系统的可维护性和可扩展性。
-
抽象不应该依赖细节:抽象层(如接口或抽象类)定义了模块之间的交互规则,而不应该依赖于具体的实现细节。这意味着抽象层的设计应该独立于具体的实现,以便于后续的替换和维护。
-
细节应该依赖抽象:具体的实现类(细节)应该实现抽象层定义的接口或继承抽象类,从而确保它们的行为符合抽象层的规范。这样,当需要更换具体的实现时,只要新的实现类符合抽象层的规范,就可以无缝地替换旧的实现类,而不需要修改高层模块的代码。
依赖倒置原则强调通过依赖于抽象接口而不是具体实现,可以减少代码之间的直接依赖,使得代码更加模块化、可重用,并且更容易进行单元测试和维护。此外,这一原则也是面向对象设计中的一个重要概念,它强调了抽象化的重要性,并通过抽象化来降低代码之间的耦合度,提高软件的质量和可维护性。
3. 依赖倒置原则应用场景
- 设计模式:例如工厂模式、策略模式等,都是依赖倒置原则的应用实例。
- 分层架构:在MVC(模型-视图-控制器)或分层软件体系结构中,每一层依赖于上一层提供的接口或抽象类。
- 微服务架构:服务间通过接口通信,而非直接互相依赖。
4. 依赖倒置原则优点
依赖倒置原则(Dependency Inversion Principle, DIP)有以下几个显著的优点:
-
高内聚,低耦合:通过依赖于抽象接口或抽象类,降低了组件之间的相互依赖,使得修改或替换底层实现变得更容易,减少了“牵一发而动全身”的风险,提高了代码的独立性和稳定性。
-
灵活性:由于高层模块与具体实现解耦,可以方便地添加、删除或替换底层实现,适应不断变化的需求。例如,在测试环境中,可以用模拟实现替代生产环境中的复杂服务。
-
模块化与扩展性:每个模块只关心它应该做什么,而不关心是谁在做这件事,这有利于模块的独立开发和维护。新功能的添加通常只需要增加一个新的实现,而不必改动已有的高层模块。
-
提高可测试性:因为高层模块不直接依赖于具体实现,它们更容易单元测试。我们可以对每个模块编写单独的测试用例,而不需要担心其他部分的影响。
-
减少代码冗余:当需要修改基础逻辑时,只需在一个地方更改接口,所有依赖这个接口的地方都能自动受益,避免了代码复制和粘贴导致的问题。
-
符合开闭原则:DIP是开闭原则的具体体现,即对扩展开放,对修改关闭。这意味着增加新的功能时,只需要添加新的实现,而不是修改现有的代码。
5. 依赖倒置原则使用步骤
- 定义接口或抽象类:首先,确定业务中共享的行为并创建相应的接口或抽象类。
- 抽象高层模块:让高层模块依赖这些接口,而非具体的实现。
- 实现接口:创建具体的类并实现这些接口。
- 调用者注入依赖:在使用这些高层模块的地方,传入相应的实现对象,而非硬编码。
6. 依赖倒置原则代码示例
// 模型:抽象接口
interface PaymentService {void processPayment();
}// 具体实现:依赖倒置
class CreditCardPaymentService implements PaymentService {@Overridepublic void processPayment() { /* ... */ }
}// 控制器:高层模块,依赖抽象
class ShoppingCartController {private PaymentService paymentService;public ShoppingCartController(PaymentService service) {this.paymentService = service;}public void checkout() {paymentService.processPayment();}
}// 测试时更换支付服务
public class Test {public static void main(String[] args) {ShoppingCartController controller = new ShoppingCartController(new CreditCardPaymentService());// 或者在运行时切换为另一种支付服务controller.paymentService = new PayPalPaymentService();controller.checkout();}
}
7. 总结
综上,依赖倒置原则(Dependency Inversion Principle, DIP)是面向对象设计中的一个基本原则,它提倡高层模块不应该依赖于低层模块,而是两者都应该依赖于抽象。简单来说,就是“针对接口编程,而不是针对实现”。
这个原则鼓励我们编写可测试、灵活和易于维护的代码,通过接口或抽象类来规定系统组件之间的交互,使得当底层实现改变时,高层模块不需要做修改,只需要关注接口的变化即可。这有助于降低系统的耦合度,提高整体架构的稳定性。
相关文章:

设计模式六大原则之:依赖倒置原则
1. 依赖倒置原则简介 依赖倒置原则(Dependency Inversion Principle, DIP) 是面向对象设计的核心原则之一,由罗伯特马丁(Robert C. Martin)提出,旨在降低类间的依赖度,使之更易于维护和扩展。该原则主张高层模块不应该依赖于底层模块&#x…...
06_Linux中如何让程序重启后自动启动
Linux中如何让程序重启后自动启动 systemd单元文件1.创建服务文件!!!服务配置文件的介绍 2.需要配置服务的状态(加载和启用服务)3.验证服务程序的运行状态4.打印程序的标准输出 systemd单元文件 Systemd 是现代 Linux…...

优化业务流程的关键:深入探讨BPA流程设计
在当前竞争激烈的商业环境中,业务流程自动化(BPA)已经成为企业提升效率、减少成本和提高业务灵活性的关键工具。今天,我们将深入探讨BPA流程设计的重要性及其实施步骤,为企业提供实用的指南。 什么是BPA? …...
qt工程中调用sdl的流程
配置 Qt 工程 在你的 Qt 工程中,需要对项目文件(.pro 文件)进行配置,以包含 SDL 库的路径和链接选项。 # Qt Project File (.pro)# 设置 SDL 库的路径 INCLUDEPATH /path/to/SDL/include LIBS -L/path/to/SDL/lib -lSDL2初始化…...

ECMAScript性能优化技巧与陷阱
大家好,我是程序员小羊! 前言 ECMAScript,即JavaScript,是一种广泛应用于Web开发中的脚本语言。随着现代Web应用的复杂度日益增加,如何优化JavaScript的性能变得至关重要。性能优化不仅能提高应用的响应速度&#x…...

c++实现B树(上)
哈喽啊!好久不见,甚是想念!失踪人口要回归了,时隔一个多月小吉我终于要更新blog了🎉。在停更的一个多月中,小吉也有在好好学习提升自己,立志给大家呈现好文章。 现在让我们进入正题吧…...

【机器学习】深度强化学习–RL的基本概念、经典场景以及算法分类
引言 深度强化学习(Deep Reinforcement Learning, DRL)是机器学习的一个分支,它结合了深度学习(Deep Learning)和强化学习(Reinforcement Learning, RL)的技术 文章目录 引言一、深度强化学习–…...

【git】将本地文件上传到github
安装git 选择一个文件夹作为git仓库,cd到文件夹输入 git init文件夹出现.git文件夹,该文件夹默认为隐藏文件夹,设置为不隐藏 在cmd中输入 ssh-keygen -t rsa -C "xxxxxx.com"该邮箱为github邮箱,然后一路enter出现以…...

安卓应用开发学习:手机摇一摇功能应用尝试--摇骰子和摇红包
一、引言 前几天,我发布的日志《安卓应用开发学习:查看手机传感器信息》记录了如何查看手机传感器的信息,通过上述的方法,可以看到我的OPPO手机支持19种传感器。本篇日志就记录一下常见的加速度传感器的典型应用——“摇一摇”功…...

HTML中的<fieldset>标签元素框的使用
HTML 提供的 <fieldset> 标签用于在表单中分组相关元素。 <fieldset> 标签会在相关元素周围绘制一个框。 <legend> 标签为 fieldset 元素定义标题。 语法如下: <fieldset><legend>标题</legend><!-- 元素内容... -->…...

Linux驱动入门实验班——SR501红外模块驱动(附百问网视频链接)
目录 一、工作方式 二、接口图 三、编写思路 1.构造file_operations结构体 2.实现read函数 3.编写入口函数 4.编写中断处理函数 5.编写出口函数 6.声明出入口函数以及协议 四、源码 五、课程链接 一、工作方式 SR501人体红外感应模块有两种工作模式: …...
windows C++- Com技术简介(上)
在介绍C和winrt与COM组件技术的关系之前,有必要介绍一下com组件技术,这项技术比较古老,但是它一直作为windows的基石存在。COM 是一类独立于平台且面向对象的分布式系统,用于创建可交互的二进制软件组件。 COM 技术是 Microsoft O…...

Jenkins持续集成工具学习
一、从装修厨房看项目开发效率优化 二、持续集成工具 三、JavaEE项目部署方式对比 四、JenkinsSVN持续集成环境搭建 五、JenkinsGitHub持续集成环境搭建...
Redis:查询是否包含某个字符/字符串之三
上一篇:Redis:查询是否包含某个字符/字符串之二-CSDN博客 摘要: 遍历key,在跟进value的类型遍历value是否包含指定字符串 search_strings ,这里使用redis-py库,默认只能处理utf-8编码,如果存在…...

【Redis】数据类型详解及其应用场景
目录 Redis 常⻅数据类型预备知识基本全局命令小结 数据结构和内部编码单线程架构引出单线程模型为什么单线程还能这么快 Redis 常⻅数据类型 Redis 提供了 5 种数据结构,理解每种数据结构的特点对于 Redis 开发运维⾮常重要,同时掌握每种数据结构的常⻅…...

PARA-Drive:设计并行模型实现端到端自动驾驶
论文链接 https://openaccess.thecvf.com/content/CVPR2024/papers/Weng_PARA-Drive_Parallelized_Architecture_for_Real-time_Autonomous_Driving_CVPR_2024_paper.pdfhttps://openaccess.thecvf.com/content/CVPR2024/papers/Weng_PARA-Drive_Parallelized_Architecture_fo…...
vs2022 x64 C/C++和汇编混编 遇到的坑
vs2022 x64 C/C和汇编混编 遇到的坑 遇到的问题二、问题复现1.出错代码2.问题分析2.1 堆栈对齐问题 3.解决方案 总结奇数和偶数个寄存器的影响为什么 sub rsp, 8 对奇数个寄存器有用?结论 遇到的问题 0x00007FFFFAE24A29 (msvcp140.dll)处(位于 TestCompileConsole…...

PHP概述、环境搭建与基本语法讲解
目录 【学习目标、重难点知识】 什么是网站? 1. PHP 介绍 1.1. PHP 概述 1.1.1. PHP 是什么? 1.1.2. PHP 都能做什么? 1.2. PHP 环境搭建 1.2.1. PhpStudy 2. PHP 基本语法 2.1. PHP 语法入门 2.1.1. 第一个 PHP 程序 2.1.2. PHP …...

实现信创Linux麦克风摄像头录制(源码,银河麒麟、统信UOS)
随着信创国产化浪潮的来临,在国产操作系统上的应用开发的需求越来越多,其中一个就是需要在银河麒麟或统信UOS上实现录制摄像头视频和麦克风声音,将它们录制成一个mp4文件。那么这个要如何实现了? 一. 技术方案 要完成这些功能&a…...

深度学习9--目标检测
1.概念介绍 目标检测不仅可以检测数字,而且可以检测动物的种类、汽车的种类等。例如,自动驾驶车辆需要自动识别前方物体是车辆还是行人,需要自动识别道路两 旁的指示牌和前方的红绿灯颜色。对于自动检测的算法,有两个要求…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...