1.定义:

  高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
  抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

2.使用场景:

  类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。即将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

3.使用特点

  依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
    依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
      在引入抽象层后,系统将具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。
      在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

4.实现案例

  依赖倒置原则的核心思想是面向接口编程,我们依旧用一个例子来说明面向接口编程比相对于面向实现编程好在什么地方。场景是这样的:闲着无聊看书。代码如下:
class Book{
public String getContent(){
return "书中的故事";
}
}
class Mother{
public void narrate(Book book){
System.out.println("闲着无聊");
System.out.println(book.getContent());
}
}
public class Client{
public static void main(String[] args){
Mother mother = new Mother();
mother.narrate(new Book());
}
}
运行结果:
闲着无聊
书中的故事
 
  运行良好,假如有一天,需求变成这样:不是给书而是给一份报纸,报纸的代码如下:
class Newspaper{
  public String getContent(){
    return "报纸上的新闻";
  }
}

  这时候竟然不能读报纸! 只是将书换成报纸,居然必须要修改Mother才能读。假如以后需求换成杂志呢?换成网页呢?还要不断地修改Mother,这显然不是好的设计。原因就是Mother与Book之间的耦合性太高了,必须降低他们之间的耦合度才行。

  我们引入一个抽象的接口IReader。读物,只要是带字的都属于读物:
interface IReader{
public String getContent();
}
  Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,他们各自都去实现IReader接口,这样就符合依赖倒置原则了,代码修改为:
class Newspaper implements IReader {
  public String getContent(){
    return "报纸上的新闻";
  }
}
class Book implements IReader{
  public String getContent(){
    return "书中的故事";
  }
}
class Mother{
  public void narrate(IReader reader){
    System.out.println("闲着无聊");
    System.out.println(reader.getContent());
  }
}
public class Client{
  public static void main(String[] args){
    Mother mother = new Mother();
    mother.narrate(new Book());
    mother.narrate(new Newspaper());
  }
}

运行结果:

闲着无聊
书中的故事
闲着无聊
报纸上的新闻
 
  这样修改后,无论以后怎样扩展Client类,都不需要再修改Mother类了。这只是一个简单的例子,实际情况中,代表高层模块的Mother类将负责完成主要的业务逻辑,一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。
  采用依赖倒置原则给多人并行开发带来了极大的便利,比如上例中,原本Mother类与Book类直接耦合时,Mother类必须等Book类编码完成后才可以进行编码,因为Mother类依赖于Book类。修改后的程序则可以同时开工,互不影响,因为Mother与Book类一点关系也没有。参与协作开发的人越多、项目越庞大,采用依赖导致原则的意义就越重大。现在很流行的TDD开发模式就是依赖倒置原则最成功的应用。

5.注意事项

  传递依赖关系有三种方式,以上的例子中使用的方法是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式一定不会陌生。
在实际编程中,我们一般需要做到如下3点:
(1)低层模块尽量都要有抽象类或接口,或者两者都有。
(2)变量的声明类型尽量是抽象类或接口。
(3)使用继承时遵循里氏替换原则。
  依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

设计模式原则(3)--Dependency Inversion Principle(DIP)--依赖倒转原则的更多相关文章

  1. 面象对象设计原则之五:依赖倒置原则(The Dependency Inversion Principle,DIP)

    如果说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要实现机制之一,它是系统抽象化的具体实现.依赖倒转原则是Robert C. Martin在1996年为“C++Reporte ...

  2. 北风设计模式课程---依赖倒置原则(Dependency Inversion Principle)

    北风设计模式课程---依赖倒置原则(Dependency Inversion Principle) 一.总结 一句话总结: 面向对象技术的根基:依赖倒置原则(Dependency Inversion ...

  3. 依赖倒置原则(Dependency Inversion Principle)

    很多软件工程师都多少在处理 "Bad Design"时有一些痛苦的经历.如果发现这些 "Bad Design" 的始作俑者就是我们自己时,那感觉就更糟糕了.那么 ...

  4. 面向对象设计原则 依赖倒置原则(Dependency Inversion Principle)

    依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现. 简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块 ...

  5. 六大设计原则(三)DIP依赖倒置原则

    依赖倒置原则DIP(Dependence Inversion Principle) 依赖倒置原则的含义 高层模块不能依赖低层模块,二者都应该依赖其抽象. 抽象不应该依赖于细节. 细节应该依赖抽象. 什 ...

  6. 依赖倒置原则(Dependence Inversion Principle,DIP)

    依赖倒转原则就是 A.要依赖于抽象,不要依赖于实现.(Abstractions should not depend upon details. Details should depend upon a ...

  7. 设计模式之依赖倒转原则(DIP)

    1.概念 DIP:Dependency Inversion Principle 抽象不应当依赖于细节,细节应当依赖于抽象(说通俗点也就是要针对接口编程,不要针对实现编程:或者要依赖于抽象,不要依赖于具 ...

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

    目录 背景 说明 例子 "倒置"的解释 总结 参考资料 背景 这几天组内的人一起学习DDD,里面再次提到了依赖倒置原则,在这学习过程中,大家又讨论了一下依赖倒置原则. 说明 采用依 ...

  9. IOC-控制反转(Inversion of Control),也成依赖倒置(Dependency Inversion Principle)

    基本简介 IoC 亦称为 “依赖倒置原理”("Dependency Inversion Principle").差不多所有框架都使用了“倒置注入(Fowler 2004)技巧,这可 ...

随机推荐

  1. jQuery扩展方法笔记

    一.方式列表: 1.jQuery.extend(Object); // jQuery 本身的扩展方法 2.jQuery.fn.extend(Object); // jQuery 所选对象扩展方法 二. ...

  2. Android之RecyclerView入门

    首先来实现最简单的列表展示,如图 在这个展示中,RecyclerView的作用仅限于回收和定位屏幕上的TextView,在用户滑动屏幕时,会把上一个视图回收掉,并显示下一个页面的视图,也就是回收再利用 ...

  3. C# 调用.exe文件

    process da = new process(); da.startinfo.filename = @""D:\BM0002\BM0002.exe";  //要调用的 ...

  4. MongoDB 系列(一) C# 简易入门封装

    之前写过一篇关于MongoDB的封装 发现太过繁琐 于是打算从新写一篇简易版 1:关于MongoDB的安装请自行百度,进行权限认证的时候有一个小坑,3.0之后授权认证方式默认的SCRAM-SHA-1模 ...

  5. linux用户及权限管理

    [文件管理.管道.用户及组管理.用户及权限管理]\用户及组管理 用户与组管理 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这 ...

  6. 原生JSdom节点相关(非原创)

    节点属性 Node.nodeName //返回节点名称,只读 Node.nodeType //返回节点类型的常数值,只读 Node.nodeValue //返回Text或Comment节点的文本值,只 ...

  7. 内核对象kobject和sysfs(2)——kref分析

    内核对象kobject和sysfs(2)--kref分析 在介绍ref之前,先贴上kref的结构: struct kref { atomic_t refcount; }; 可以看到,kref只是包含一 ...

  8. 单双引号的区别,defined容易疏忽的小地方

    单双引号的区别(面试题)                    1.双引号可以解析变量,单引号不行                    2.双引号解析转义字符,单引号不解析转义字符.但是单引号能解析 ...

  9. 移动APP云测试平台测评分析

    随着智能手机的普及率和渗透率越来越高,App开发软件也越来越多.有专家预测,2017年的App应用下载量将会突破2500亿,整个移动科技市场规模将会达到770亿美元.身处在这个"移动&quo ...

  10. 最短路之Floyd算法

    1.介绍 floyd算法只有五行代码,代码简单,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3),可以求多源最短路问题. 2.思想: Floyd算法的基本思想如下:从任意节点A到任意节点 ...