Java设计模式七大原则-依赖倒转原则

news/2024/11/29 18:45:00/

✨作者:猫十二懿

❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github

🎉公众号:猫十二懿

依赖倒转原则

1、依赖倒转原则

Java中的依赖倒转原则(Dependency Inversion Principle,DIP)是指高层模块不应该依赖低层模块,而是应该通过抽象来互相依赖。

  1. 高层模块不应该依赖低层模块,二者都应该依赖其抽象。

  2. 抽象不应该依赖细节,细节应该依赖抽象。

    在进行程序设计时,需要尽量避免使用具体类作为参数、变量或返回值类型等,而应该使用抽象类型。

  3. 依赖倒转 (倒置) 的中心思想是面向接口编程。

  4. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在Java中,抽象指的是接口或抽象类,细节就是具体的实现类。

  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

2、违反DIP原则

违反依赖倒转原则的Java程序可能会造成以下问题:

  • 导致代码耦合度过高。如果高层模块依赖于低层模块,那么这两个模块之间的耦合度将非常高,而且修改其中一个模块可能会影响到另一个模块。
  • 限制了代码的可扩展性。如果高层模块依赖于低层模块,那么在添加新功能或修改现有功能时,可能需要修改多个模块的代码,这将使代码的可扩展性降低。
  • 增加了代码的风险和复杂性。如果高层模块依赖于低层模块,那么这些模块之间的关系将变得非常复杂,同时也会增加代码出错的风险。
public class UserService {private MySQLDatabase database;public UserService() {database = new MySQLDatabase();}public User getUser(int id) {return database.getUser(id);}
}public class MySQLDatabase {public User getUser(int id) {// 从MySQL数据库获取用户信息}
}

在这个示例程序中,UserService依赖于MySQLDatabase。这意味着,如果需要将MySQLDatabase替换为另一个数据库,就必须修改UserService的代码,这将导致代码耦合度过高,并限制了程序的可扩展性。

正确的做法应该是将UserService改为依赖于一个抽象的IDatabase接口,而不是具体的MySQLDatabase类。

3、遵循DIP原则

public interface IDatabase {User getUser(int id);
}public class MySQLDatabase implements IDatabase {public User getUser(int id) {// 从MySQL数据库获取用户信息}
}public class UserService {private IDatabase database;public UserService(IDatabase database) {this.database = database;}public User getUser(int id) {return database.getUser(id);}
}

在这个修改后的程序中,UserService不再依赖于具体的MySQLDatabase类,而是依赖于IDatabase接口,因此这个程序遵循了依赖倒转原则。

同时,我们还将MySQLDatabase类实现了IDatabase接口,这样当我们需要将MySQLDatabase替换为另一个数据库时,只需要提供一个新的实现了IDatabase接口的类即可,并不需要修改UserService的代码。这样就提高了代码的可扩展性。

4、依赖关系传递的三种方式

4.1 接口传递

/*** 方式1: 通过接口传递实现依赖*/interface IOpenAndClose1 {public void open(ITV1 tv); //抽象方法,接收接口}interface ITV1 { //ITV接口public void play();}class OpenAndClose1 implements IOpenAndClose1 {@Overridepublic void open(ITV1 tv){tv.play();}
}class ChangHong1 implements ITV1 {@Overridepublic void play() {System.out.println("打开电视机");}}public class DependencyPass1 {public static void main(String[] args) {ChangHong1 changHong = new ChangHong1();OpenAndClose1 openAndClose = new OpenAndClose1();openAndClose.open(changHong);}
}

4.2 构造方法传递

/*** 方式2: 通过构造方法依赖传递*/interface IOpenAndClose2 {public void open(); //抽象方法}interface ITV2 { //ITV接口public void play();}class OpenAndClose2 implements IOpenAndClose2 {public ITV2 tv; //成员public OpenAndClose2(ITV2 tv){ //构造器this.tv = tv;}public void open(){this.tv.play();}}class ChangHong2 implements ITV2 {public void play() {System.out.println("长虹电视机,打开");}
}public class DependencyPass2 {public static void main(String[] args) {ChangHong2 changHong = new ChangHong2();//通过构造器进行依赖传递OpenAndClose2 openAndClose = new OpenAndClose2(changHong);openAndClose.open();}
}

4.3 setter方法传递

/*** 方式3: 通过setter方法传递*/
interface IOpenAndClose3 {public void open(); // 抽象方法public void setTv(ITV3 tv);
}interface ITV3 { // ITV接口public void play();
}class OpenAndClose3 implements IOpenAndClose3 {private ITV3 tv;public void setTv(ITV3 tv) {this.tv = tv;}public void open() {this.tv.play();}
}class ChangHong3 implements ITV3 {public void play() {System.out.println("长虹电视机,打开");}
}public class DependencyPass3 {public static void main(String[] args) {ChangHong3 changHong = new ChangHong3();//通过setter方法进行依赖传递OpenAndClose3 openAndClose = new OpenAndClose3();openAndClose.setTv(changHong);openAndClose.open();}
}

5、DIP总结

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

http://www.ppmy.cn/news/88974.html

相关文章

springboot+vue之java学习平台(java项目源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的java学习平台。项目源码以及部署相关请联系风歌,文末附上联系信息 。 💕💕作者:风歌&a…

The Open Graph protocol(开放图谱协议)的介绍及应用

介绍 Open Graph 协议使任何网页都可以成为社交中的丰富对象。例如,用于 Facebook 以允许任何网页具有与 Facebook 上任何其他对象相同的功能。 以下是把链接分享到钉钉,钉钉识别后显示的效果: 基本元数据 要将网页变成图形对象&#xff0…

openGauss Developer Day 2023 | 邀您参加海量数据分论坛

尊敬的数据库开发者 : 海量数据 已为您备好一封通往数智时代的邀请函,请您于 5月26日 前往北京昆泰嘉瑞文化中心,赶赴 openGauss Developer Day 2023 的盛大约定。 本次专场活动中,海量数据将会轮番为您展示最核心的技术…

关于信号包络检测

说明 最近在调研学习数字滤波的东西,看到关于信号包络检测这样一个知识点,感觉很有意思,于是想着简单捋清楚并写篇博文装载起来总结一下。本博文与车载毫米波雷达的信号和数据处理无关,所以本文不会放到车载毫米波雷达系列专题规划…

代码随想录算法训练营第49天 | 121、122

121. 买卖股票的最佳时机 题目描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回…

Reid strong baseline 代码详解

本项目是对Reid strong baseline代码的详解。项目暂未加入目标检测部分,后期会不定时更新,请持续关注。 本相比Reid所用数据集为Markt1501,支持Resnet系列作为训练的baseline网络。训练采用表征学习度量学习的方式。 目录 训练参数 训练代…

URLConnection(三)

文章目录 1. 配置连接2. protected URL url3. protected boolean connected4. protected boolean allowUserInteraction5. protected boolean doInput5. protected boolean doOutput6. protected boolean isModifiedSince7. protected boolean useCaches8. 超时 1. 配置连接 U…

[PyTorch][chapter 35][经典卷积神经网络-1 ]

前言: ILSVRC(ImageNet Large Scale Visual Recognition Challenge)是近年来机器视觉领域最受追捧也是最具权威的学术竞赛之一,代表了图像领域的最高水平。 ImageNet数据集是ILSVRC竞赛使用的是数据集,由斯坦福大学李…