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 肌电信号直方图…

Day41:198.打家劫舍、213.打家劫舍II、337.打家劫舍 III

文章目录 198.打家劫舍思路代码实现 213.打家劫舍II思路代码实现 337.打家劫舍 III思路代码实现记忆化递归法(其他解法) 198.打家劫舍 题目链接 思路 确定dp数组(dp table)以及下标的含义 dp[i]:考虑下标i以内的房屋…

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

项目要求&#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("…

mysql中TIMESTAMP 和DATETIME数据类型的区别

在MySQL中&#xff0c;TIMESTAMP和DATETIME都用于表示日期和时间&#xff0c;但是它们之间存在一些关键区别。下面我们通过几个关键点来详细了解这两种数据类型的使用&#xff1a; 存储范围 TIMESTAMP类型的存储范围从1970-01-01 00:00:01 UTC到2038-01-19 03:14:07 UTC。DAT…

Django之importlib模块

【1】介绍 import importlib importlib模块是Python中用于动态加载和导入模块的内置模块 它提供了一组函数和类&#xff0c;使得我们可以在运行时根据需要加载模块&#xff0c;并且可以对已导入的模块进行操作和管理 【2】importlib模块中的import_module方法 【2.1】导入模块…

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

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

武汉光庭公司地图引擎开发工程师24秋招三场面试完整流程

本文介绍2024届秋招中&#xff0c;武汉光庭信息技术股份有限公司的智能驾驶地图引擎开发工程师岗位一面、二面、三面的面试基本情况、提问问题等。 10月投递了武汉光庭信息技术股份有限公司的智能驾驶地图引擎开发工程师岗位&#xff0c;暂时并不清楚所在的部门。目前完成了全部…

mysql:修改密码的几种方式

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

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

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

DP好题总结

LCIS最长公共上升子序列 题解&#xff1a;https://blog.csdn.net/weixin_50624971/article/details/116892236 概括&#xff1a; 决策优化DP 考虑LCS可以写成 O ( n 4 ) O(n^4) O(n4) 的如果我们把状态设为 f [ i , j ] f[i,j] f[i,j] 表示考虑到 a [ i ] , b [ j ] a[i]…

机器学习【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;但是要…

.yaml文件的简介

文章目录 YAML文件简介YAML文件的示例 YAML文件简介 YAML是一种人类可读的数据序列化标准。它常被用于配置文件、数据交换格式、以及在一些编程语言中的数据结构描述。 YAML 文件的主要特点有如下四点&#xff1a; 可读性&#xff1a;YAML 的语法结构简洁明了&#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%;通配符字符 符…

5:kotlin 类(Classes )

kotlin支持面向对象编程&#xff0c;也有雷和对象的概念 要声明一个类需要使用class关键字 class Customer属性&#xff08;Properties&#xfeff;&#xff09; 可以在类名后边添加()&#xff0c;在()里边声明属性 class Contact(val id: Int, var email: String)声明了不…

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

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