03.依赖倒置原则(Dependence Inversion Principle)

概述

高层模块不应依赖低层模块,二者都应该依赖其抽象。而抽象不应依赖细节,细节应该依赖抽象。依赖倒置原则的中心思想其实就是面向接口编程
相对于细节的多变性,抽象的东西会稳定的多,所以以抽象为基础搭建的架构自然也会比以细节为基础搭建的架构稳定的多
使用接口或抽象类的目的是为了更好的制定规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

相信有读过spring framework源码的同学应该对这一点深以为是,比如其核心接口之一的BeanFactory接口之下就继承了AutowireCapableBeanFactory、HierarchicalBeanFactory、ListableBeanFactory接口,而这些接口又被多个抽象类有选择实现,正是对依赖倒置原则的应用才使得spring framework 框架具有了极高的健壮性和扩展性。
在这里插入图片描述

三寸反骨

我们不妨从相反的角度出发,写个反例看看会有什么问题,今日反骨颇重,就是不想遵循依赖倒置原则。
比如我们现在需要编写一个简单的Person类,让他可以接受邮件消息即可。
反例

public class DependecyInversion {public static void main(String[] args) {Person person = new Person();person.receive(new Email());}
}class Email{public String getInfo(){return "电子邮件信息: Hello,Email";}
}class Person {public void receive(Email email){System.out.println(email.getInfo());}
}

编程的过程十分愉快,如此简单的需求甚至不需要聪明的我们多思考一秒。运行效果也完全满足预期。
但是,来了一个不好不坏的消息:“能力需要扩展,客户要求,除了收到email的能力外,微信消息也想收到!”
“反骨仔想了想,不要紧,我新增类,同时Person类也要增加相应的方法就好了呀”!
于是他加班1小时完成了这个需求,自信满满的走了。
但是,第二天又来了个不好不坏的消息:“客户对产品很满意,同时要求除了想收到email、微信消息之外,还想扩展几十个软件的消息,清单包含:“QQ、微博、墨迹天气、钉钉…”
反骨仔爆炸了,因为这个需求如果继续按他的思路去实现,类也爆炸了。实现的方法更是爆炸到难以维护。
所以说一定要设计先行,一个优秀的设计可能会占据相当长的开发时间,但是会为后期的扩展和维护提供强有力的保障!


优化设计

我们把时间推回两天前,接到需求的我们首先便进行了深度剖析并达成了共识:“依赖倒置原则必须遵守!”于是,有了如下代码:

public class DependecyInversion {public static void main(String[] args) {Person person = new Person();person.receive(new Email());person.receive(new WeChat());}
}
interface IReceive{public String getInfo();
}class Email implements IReceive{public String getInfo(){return "电子邮件信息: Hello,Email";}
}class WeChat implements IReceive{public String getInfo(){return "微信信息: Hello,WeChat";}
}class Person {public void receive(IReceive receiver){System.out.println(receiver.getInfo());}
}

当客户说我要继续扩展几十个消息入口时,我们会发现,我们对于person类不需要做任何改动了,不过是需要遵照IReceive接口规范去实现新扩展的业务细节就可以了。善莫大焉。


依赖关系传递三板斧

常见的依赖关系传递有三种方式:

接口传递

public class DependencyPass {public static void main(String[] args) {ChangHong changHongTv = new ChangHong();OpenAndClose openAndClose = new OpenAndClose();openAndClose.open(changHongTv);}
}class ChangHong implements ITV,ITV2,ITV3{@Overridepublic void play() {System.out.println("长虹电视机打开了。");}
}
interface IOpenAndClose{public void open(ITV tv);
}
interface ITV{public void play();
}
//实现接口
class OpenAndClose implements IOpenAndClose{@Overridepublic void open(ITV tv) {tv.play();}
}

构造方法传递

public class DependencyPass {public static void main(String[] args) {ChangHong changHongTv = new ChangHong();OpenAndClose2 openAndClose2 = new OpenAndClose2(changHongTv);openAndClose2.open();}}
class ChangHong implements ITV,ITV2,ITV3{@Overridepublic void play() {System.out.println("长虹电视机打开了。");}
}
interface IOpenAndClose2{public void open();
}
interface  ITV2{public void play();
}
class OpenAndClose2 implements IOpenAndClose2{public ITV2 tv;public OpenAndClose2(ITV2 tv){this.tv = tv;}@Overridepublic void open() {this.tv.play();}
}

setter方法传递

public class DependencyPass {public static void main(String[] args) {ChangHong changHongTv = new ChangHong();OpenAndClose3 openAndClose3 = new OpenAndClose3();openAndClose3.setTv(changHongTv);openAndClose3.open();}}class ChangHong implements ITV,ITV2,ITV3{@Overridepublic void play() {System.out.println("长虹电视机打开了。");}
}
interface IOpenAndClose3{public void open();public void setTv(ITV3 itv3);
}
interface ITV3{public void play();
}
class OpenAndClose3 implements IOpenAndClose3{private ITV3 itv3;@Overridepublic void setTv(ITV3 itv3) {this.itv3 = itv3;}@Overridepublic void open() {this.itv3.play();}
}

  1. 底层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好;
  2. 变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间就存在一个缓冲层,利于程序扩展和优化;
  3. 继承时遵循里氏替换原则;
  4. 什么是里氏替换原则?下次讲!

关注我,共同进步,每周至少一更。——Wayne

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/167393.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EMG肌肉电信号处理合集(二)

本文主要展示常见的肌电信号特征的提取说明。使用python 环境下的Pysiology计算库。 目录 1 肌电信号第一次burst的振幅, getAFP 函数 2 肌电信号波长的标准差计算,getDASDV函数 3 肌电信号功率谱频率比例,getFR函数 4 肌电信号直方图…

华清远见嵌入式学习——网络编程——小项目

项目要求&#xff1a; 代码实现&#xff1a; 服务器端&#xff1a; #include <myhead.h>//定义协议包 struct proto {char type;char name[20];char text[128]; };int main(int argc, const char *argv[]) {//判断从终端输入的字符串的个数if(argc ! 3){printf("…

无需API开发,钱方QFPay连接营销系统和广告推广平台

随着电子商务市场的不断发展&#xff0c;企业需要集成各种业务系统&#xff0c;以提高业务效率和降低运营成本。钱方QFPay提供了一种创新的解决方案&#xff0c;帮助企业实现系统间的连接和集成&#xff0c;无需进行复杂的API开发。除了电商系统和客服系统&#xff0c;钱方还能…

mysql:修改密码的几种方式

背景 当我们 brew install mysql 新安装 mysql 的时候&#xff0c;是没有密码的&#xff0c;我们可以直接通过 mysql -u root 连接上。但是密码还是要设置的&#xff0c;一是为了安全&#xff0c;二是有些数据库软件如 Sequel 连接都是必须要密码的&#xff0c;接下来我们来看…

电磁建模的分布式并行计算技术

本文提出了一种新的分布式并行电磁建模技术&#xff0c;以加快电磁结构的神经网络建模过程。现有的电磁建模技术通常需要反复改变微波器件的参数&#xff0c;驱动电磁模拟器以获得足够的训练和测试样本。随着电磁建模问题复杂性的增加&#xff0c;由于单台计算机的性能有限&…

机器学习【00】pycharm使用远程服务器

我们使用conda在服务器上创建虚拟环境&#xff0c;远程使用pycharm进行编程 pycharm版本2023.1.3 一.首先在服务器上创建虚拟环境 注&#xff1a;anaconda的安装可以参考ubuntu系统miniconda的安装 conda create --name tac python3.7二.pycharm 连接 点击add interpreter …

查企业联系电话的方法

对于销售来说&#xff0c;获取准确、全面的企业联系方式&#xff0c;无疑是开发客户的基础与保障&#xff0c;因为任凭能力再高&#xff0c;说服能力多强&#xff0c;没有与客户接触的机会&#xff0c;这些都是无稽之谈。但是大家都知道&#xff0c;道理都懂&#xff0c;但是要…

报错AttributeError: module ‘cv2‘ has no attribute ‘ximgproc‘

报错AttributeError: module ‘cv2’ has no attribute ‘ximgproc’ 首先查看是否安装opencv-contrib-python pip list | grep opencv显示 opencv-contrib-python 4.4.0.46 opencv-python 4.8.1.78 opencv-pyt…

【2023.11.24】Mybatis基本连接语法学习➹

基本配置 1.如果使用Maven管理项目&#xff0c;需要在pom.xml中配置依赖。 2.安装Mybatis-3.5.7.jar包 3.进行XML配置&#xff1a;这里将文件命名为mybatis-config.xml 配置数据库连接XML文件 <?xml version"1.0" encoding"UTF-8" ?> <!DO…

Crypto(10)BUUCTF-RSA3(共模攻击)

一.共模攻击的现实意义 好奇一个问题&#xff0c;即共模攻击有什么现实意义&#xff1f; 发现也没有什么现实意义&#xff0c;因为&#xff08;n,e&#xff09;是已知的&#xff0c;通常每个用户的n是不同的&#xff0c;除非特殊情况吧 二.共模攻击的数学原理&#xff1a; 通…

最重要的BI测试-适用于任何BI和分析平台

为什么 BI 测试是答案 相信你的数据可视化是成功执行商业智能 (BI) 和分析项目的关键因素。我敢肯定&#xff0c;你遇到过以下情况&#xff1a;业务主管或业务用户反馈说他们的分析看起来不对&#xff0c;他们的 KPI 看起来有问题&#xff0c;或者速度太慢而无法使用。要问自己…

SQL 通配符:用于模糊搜索和匹配的 SQL 关键技巧

SQL通配符字符 通配符字符用于替代字符串中的一个或多个字符。通配符字符与LIKE运算符一起使用。LIKE运算符用于在WHERE子句中搜索列中的指定模式。 示例 返回所有以字母 ‘a’ 开头的客户&#xff1a; SELECT * FROM Customers WHERE CustomerName LIKE a%;通配符字符 符…

单片机、ARM、嵌入式开发、Android 底层开发有什么关系?

单片机、ARM、嵌入式开发、Android 底层开发有什么关系&#xff1f; 从我目前的见识来看&#xff1a; 单片机是个系统&#xff08;比如&#xff1a;51、AVR、PLC...&#xff09;&#xff0c;其中包含了去除了输入输出之外的运算器、控制器、存储器&#xff0c;我们用程序可以非…

从Redis反序列化UserDetails对象异常后发现FastJson序列化的一些问题

最近在使用SpringSecurityJWT实现认证授权的时候&#xff0c;出现Redis在反序列化userDetails的异常。通过实践发现&#xff0c;使用不同的序列化方法和不同的fastJson版本&#xff0c;异常信息各不相同。所以特地记录了下来。 一、项目代码 先来看看我项目中redis相关配置信息…

黑马点评笔记 redis缓存三大问题解决

文章目录 缓存问题缓存穿透问题的解决思路编码解决商品查询的缓存穿透问题 缓存雪崩问题及解决思路缓存击穿问题及解决思路问题分析使用锁来解决代码实现 逻辑过期方案代码实现 缓存问题 我们熟知的是用到缓存就会遇到缓存三大问题&#xff1a; 缓存穿透缓存击穿缓存雪崩 接…

【Spring篇】JDK动态代理

目录 什么是代理&#xff1f; 代理模式 动态代理 Java中常用的代理模式 问题来了&#xff0c;如何动态生成代理类&#xff1f; 动态代理底层实现 什么是代理&#xff1f; 顾名思义&#xff0c;代替某个对象去处理一些问题&#xff0c;谓之代理&#xff0c;那么何为动态&a…

短视频账号矩阵系统saas化批量管理部署搭建/技术

一、短视频矩阵系统建模----技术api接口--获取用户授权 技术文档分享&#xff1a; 本系统采用MySQL数据库进行存储&#xff0c;数据库设计如下&#xff1a; 1.用户表&#xff08;user&#xff09;&#xff1a; - 用户ID&#xff08;user_id&#xff09; - 用户名&#xff08;…

【理解ARM架构】操作寄存器实现UART | 段的概念 | IDE背后的命令

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《理解ARM架构》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f360;操作寄存器实现UART&#x1f35f;UART原理&#x1f35f;编程 &#x1f360;…

python——第十二天

内置模块或者其他模块学习方式&#xff1a; dir help os模块负责程序与操作系统的交互&#xff0c;提供了访问操作系统底层的接口&#xff1b;即os模块提供了非常丰富的方法用来处理文件和目录。 os&#xff1a; os.path 遍历C盘代码 import os from os import path def …

修改YOLOv5的模型结构第三弹

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 文章目录 任务任务拆解 开始修改C2模块修改yolo.py修改模型配置文件 模型训练 上次已…