设计模式原则之依赖倒转(倒置)原则

原则概述

依赖倒转原则(Dependence Inversion Principle)是指: 高层模块不应该依赖底层模块,二者都应该依赖其(或接口)抽象(不要依赖具体子类) 。也就是说 抽象不应该依赖于细节,细节应当依赖于抽象;其核心思想是要面向接口编程,而不是面向实现编程。

实现方法

具体来说,当我们在代码中传递参数或搭建关联关系时,尽量引用层次高的抽象层类,也就是尽量使用接口和抽象类代替具体类来进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,尽量不要用具体类来做这些事情。

为了确保该原则的有效使用,就要遵守接口隔离原则,即一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法;否则将无法调用在子类中增加的新方法。

引入抽象层后,系统将具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

实现了依赖倒转原则,我们更多的时候是针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其对应的抽象层中;
依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。
常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

小结

依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则:
1、每个类尽量提供接口或抽象类,或者两者都具备。
2、变量的声明类型尽量是接口或者是抽象类。
3、任何类都不应该从具体类派生。
4、使用继承时尽量遵循里氏替换原则

应用案例

比如有个Person类,可以接受Email、QQ和微信的消息。如果都为其提供一个专门的方法,就会让代码非常的冗余:

可以引入一个IReceiver接口,让Person类依赖该接口。这样QQ类、微信类和Email类各自实现IReceiver里面的方法即可:

对应的代码如下,

编程完成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,world";}
}
//完成Person接收消息的功能
//方式1分析
//1. 实现简单,比较容易想到
//2. Person类的receive方法直接接收了一个Email,问题是如果我们获取的对象是除了Email,
//还有从 微信,短信中获取信息 等等,则需要新增类,同时Perons也要增加相应的接收方法
//3. 解决思路:引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖
//   因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就ok, 这样我们就符号依赖倒转原则
class Person {public void receive(Email email ) {System.out.println(email.getInfo());}
}

​ Person类的receive方法直接接收了一个Email,问题是如果我们获取的对象是除了Email,还想要从 微信,短信等对象中获取信息 等等,这样我们就需要新增类,同时Perons也要增加相应的接收方法。

​ 解决方法:引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖, 因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就可以了, 这样我们就符合依赖倒转原则,而Person类不需要新增相应的接收方法,只需要将Person类的receive方法的参数变成IReceiver接口即可。

 public class DependecyInversion {public static void main(String[] args) {//客户端无需改变Person person = new Person();person.receive(new Email());person.receive(new WeiXin());}
}
//定义接口
interface IReceiver {public String getInfo(); //做成抽象方法
}
class Email implements IReceiver {public String getInfo() {return "电子邮件信息: hello,world";}
}
//增加微信,实现IReceiver
class WeiXin implements IReceiver {public String getInfo() {return "微信信息: hello,ok";}
}
//方式2
class Person {//这里我们是对接口的依赖public void receive(IReceiver receiver ) {System.out.println(receiver.getInfo());}
}

依赖关系传递的三种方式和应用案例
  1. 接口传递
// 方式1: 通过接口传递实现依赖
// 开关的接口
interface IOpenAndClose {public void open(ITV tv); // 抽象方法,接收接口
}interface ITV { // ITV接口public void play();
}class ChangHong implements ITV {@Overridepublic void play() {// TODO Auto-generated method stubSystem.out.println("长虹电视机,打开");}
}
 实现接口
class OpenAndClose implements IOpenAndClose {public void open(ITV tv) {tv.play();}
}
  1. 构造方法传递
//方式2:通过构造方法依赖传递
interface IOpenAndClose {public void open(); // 抽象方法
}interface ITV { // ITV接口public void play();
}class OpenAndClose implements IOpenAndClose {public ITV tv; // 成员public OpenAndClose(ITV tv) { // 构造器this.tv = tv;}public void open() {this.tv.play();}
}
  1. setter方式传递
// 方式3 , 通过setter方法传递
interface IOpenAndClose {public void open(); // 抽象方法public void setTv(ITV tv);
}interface ITV { // ITV接口public void play();
}class OpenAndClose implements IOpenAndClose {private ITV tv;public void setTv(ITV tv) {this.tv = tv;}public void open() {this.tv.play();}
}class ChangHong implements ITV {@Overridepublic void play() {// TODO Auto-generated method stubSystem.out.println("长虹电视机,打开");}

小结:

  1. 高层模块不应该依赖底层模块,二者都应该依赖其(或接口)抽象(不要依赖具体子类)

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

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

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

  5. 遵循依赖倒转的话我们在继承时遵循里氏替换原则( 里氏替换原则规定了在任意父类可以出现的地方,子类都一定可以出现 )

设计模式原则之依赖倒转(倒置)原则相关推荐

  1. 六大原则之依赖倒转(倒置)原则

    1. 依赖倒转(倒置)原则 介绍 高层模块不应该依赖低层模块,二者都应该依赖其抽象 抽象不应该依赖细节,细节应该依赖抽象 依赖倒转(倒置)的中心思想是面向接口编程 依赖倒转原则是基于这样的设计理念:相 ...

  2. Java设计模式七大原则-依赖倒转(倒置)原则

    目录 依赖倒转原则 依赖关系传递的三种方式和应用案例 1. 接口传递 2.构造方法传递 3.setter方式传递 依赖倒转原则的注意事项和细节 依赖倒转原则 基本介绍 依赖倒转原则(Dependenc ...

  3. 浅谈设计模式-依赖倒转(倒置)原则

    书接上回,本篇继续讲一下设计模式六大原则(有些书认为是7大原则) 原则定义 1>高层次的模块不要依赖低层次的模块,二者都应该依赖于其抽象 2>抽象不应该依赖于具体,而是具体应该依赖于抽象 ...

  4. 设计模式常用的七大原则之③【依赖倒转】原则

    文章目录 概念 案例 代码1.0 解决思路 依赖关系传递的三种方式和应用案例 接口传递 构造方法传递 set传递 依赖倒转原则的注意事项和细节 概念 依赖倒转原则(Dependence Inversi ...

  5. 【设计模式】七大原则之“依赖倒转原则”

    一 基本介绍 依赖倒转原则(Dependence Inversion Principle)是指: 高层模块不应该依赖低层模块,二者都应该依赖其抽象 抽象不应该依赖细节,细节应该依赖抽象 依赖倒转(倒置 ...

  6. java依赖倒转原则_设计原则之--依赖倒转原则

    [各位博友晚上好,又到了晚上的这个时间,感谢大家一直对Darren博客的支持,希望这篇文章对你有所帮助: 这几天一直在看设计模式:简单工厂模式,策略模式,单一职责原则,开放 [依赖倒转原则又称依赖倒置 ...

  7. 面向对象编程原则(06)——依赖倒转原则

    版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 参考资料 <大话设计模式> 作者:程杰 <Java设计模式> 作者:刘 ...

  8. Java里氏转换_里氏代换原则、依赖倒转原则 | 学步园

    里氏代换原则 面向对象设计的重要原则是创建抽象化,并且从抽象化导出具体化,具体化也就是给出不同的实现. 继承关系就是一种从抽象化到具体化的导出. 里氏代换原则:如果对每一个类型为T1的对象o1,都有类 ...

  9. 设计模式 学习笔记(2)单一职责原则、开放封闭原则、依赖倒转原则

    (3)单一职责原则 单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因.例如,我们在写一个窗体应用程序,一般都会生成一个Form这样的类,于是我们就把各种各样的代码,像算法.数据库访问 ...

最新文章

  1. 人群计数--Cross-scene Crowd Counting via Deep Convolutional Neural Networks
  2. SIFT四部曲之——构建关键点特征描述符
  3. Python档案袋(列表、元组、字典、集合 )
  4. Using jQuery to add a dynamic “Back To Top” floating button with smooth scroll
  5. ENode 2.8 最新架构图简介
  6. linux文件读保护,Linux Rootkit实现文件保护
  7. 不需要安全实验证也可以开微信号_热门行业:电子专用设备工程师证考试报名时间及报名须知...
  8. iplatui---弹窗
  9. rust显卡要求 steam_Steam夏促游戏销量排行,Epic称暂时不要买地平线黎明时分,虚幻5引擎配置要求不高,热血无赖电影开拍,Steam夏促育碧专区...
  10. 第三天.SQL语言基础
  11. 创建、删除swap分区
  12. Python检查批量URL是否可以正常访问
  13. 基于python人脸光照不均匀数据的制作
  14. 从零开始写一个Jison解析器(3/10):良好的开端是成功的一半——《政治学》 (亚里士多德)
  15. 公司法人代表变更需要多少钱?
  16. 深入理解MyBatis(七)—MyBatis事务
  17. 零停机给Kubernetes集群节点打系统补丁
  18. Int类型变量的取值范围为何是2的31次方?
  19. shell中的流编辑器awk
  20. 即学即会---简单易学模拟时钟 (html +css +js)

热门文章

  1. linux共享内存 pmu,基于ARM的GPS-无源北斗互备PMU研究与设计
  2. sql server XML中value(),exists(),nodes()方法
  3. 铁路一线工人春运备战实录:深夜里的“钢铁工匠”
  4. 货币时间价值(学习笔记)
  5. openwrt 做二级路由 同网段无线桥接教程 relayd
  6. 【vijos】1770 大内密探(树形dp+计数)
  7. 信仰是如何毁掉程序员的
  8. 什么是生物特征识别?有哪些生物特征?
  9. vue的多标签页实现
  10. mes系统故障_mes系统实施失败是什么原因?