`

设计模式六大原则(3):依赖倒置原则

 
阅读更多

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。

解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

         依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在Java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

         依赖倒置原则的核心思想是面向接口编程,我们依旧用一个例子来说明面向接口编程比相对于面向实现编程好在什么地方。场景是这样的,母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。代码如下:

[java] view plain
  1. class Book{  
  2.     public String getContent(){  
  3.         return "很久很久以前有一个阿拉伯的故事……";  
  4.     }  
  5. }  
  6.   
  7. class Mother{  
  8.     public void narrate(Book book){  
  9.         System.out.println("妈妈开始讲故事");  
  10.         System.out.println(book.getContent());  
  11.     }  
  12. }  
  13.   
  14. public class Client{  
  15.     public static void main(String[] args){  
  16.         Mother mother = new Mother();  
  17.         mother.narrate(new Book());  
  18.     }  
  19. }  

运行结果:

妈妈开始讲故事
很久很久以前有一个阿拉伯的故事……

        运行良好,假如有一天,需求变成这样:不是给书而是给一份报纸,让这位母亲讲一下报纸上的故事,报纸的代码如下:

[java] view plain
  1. class Newspaper{  
  2.     public String getContent(){  
  3.         return "林书豪38+7领导尼克斯击败湖人……";  
  4.     }  
  5. }  

        这位母亲却办不到,因为她居然不会读报纸上的故事,这太荒唐了,只是将书换成报纸,居然必须要修改Mother才能读。假如以后需求换成杂志呢?换成网页呢?还要不断地修改Mother,这显然不是好的设计。原因就是Mother与Book之间的耦合性太高了,必须降低他们之间的耦合度才行。

我们引入一个抽象的接口IReader。读物,只要是带字的都属于读物:

[java] view plain
  1. interface IReader{  
  2.     public String getContent();  
  3. }  

Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,他们各自都去实现IReader接口,这样就符合依赖倒置原则了,代码修改为:

[java] view plain
  1. class Newspaper implements IReader {  
  2.     public String getContent(){  
  3.         return "林书豪17+9助尼克斯击败老鹰……";  
  4.     }  
  5. }  
  6. class Book implements IReader{  
  7.     public String getContent(){  
  8.         return "很久很久以前有一个阿拉伯的故事……";  
  9.     }  
  10. }  
  11.   
  12. class Mother{  
  13.     public void narrate(IReader reader){  
  14.         System.out.println("妈妈开始讲故事");  
  15.         System.out.println(reader.getContent());  
  16.     }  
  17. }  
  18.   
  19. public class Client{  
  20.     public static void main(String[] args){  
  21.         Mother mother = new Mother();  
  22.         mother.narrate(new Book());  
  23.         mother.narrate(new Newspaper());  
  24.     }  
  25. }  

运行结果:

妈妈开始讲故事
很久很久以前有一个阿拉伯的故事……
妈妈开始讲故事
林书豪17+9助尼克斯击败老鹰……

    这样修改后,无论以后怎样扩展Client类,都不需要再修改Mother类了。这只是一个简单的例子,实际情况中,代表高层模块的Mother类将负责完成主要的业务逻辑,一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。

    采用依赖倒置原则给多人并行开发带来了极大的便利,比如上例中,原本Mother类与Book类直接耦合时,Mother类必须等Book类编码完成后才可以进行编码,因为Mother类依赖于Book类。修改后的程序则可以同时开工,互不影响,因为Mother与Book类一点关系也没有。参与协作开发的人越多、项目越庞大,采用依赖导致原则的意义就越重大。现在很流行的TDD开发模式就是依赖倒置原则最成功的应用。

         传递依赖关系有三种方式,以上的例子中使用的方法是接口传递,另外还有两种传递方式:构造方法传递setter方法传递,相信用过spring框架的,对依赖的传递方式一定不会陌生。
在实际编程中,我们一般需要做到如下3点:

  • 低层模块尽量都要有抽象类或接口,或者两者都有。
  • 变量的声明类型尽量是抽象类或接口。
  • 使用继承时遵循里氏替换原则。

        依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

分享到:
评论

相关推荐

    设计模式六大原则

    设计模式六大原则(3):依赖倒置原则 定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。简单来说,就是模块间的依赖应建立在抽象之上,而不是具体实现上。 问题...

    设计模式六大原则与类的六种关系

    设计模式六大原则与类的六种关系 设计模式六大原则是软件设计中遵循的一些基本原则,目的是为了使软件设计更加灵活、可维护和可扩展。六大原则分别是:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、...

    设计模式之六大原则详解,Markdown笔记

    详细介绍了设计模式六大原则,配有示例代码和图片,有开闭原则,单一职责原则,里氏替换原则,依赖倒置原则,接口隔离原则,迪米特法则等等。

    php 设计模式六大原则

    php 设计模式六大原则 单一职责原则 里氏替换原则 依赖倒置原则 接口隔离原则 迪米特法则 开闭原则 word版

    JAVA设计模式六大原则详细讲解(面向对象语言通用)

    3.依赖倒置原则:面向接口编程 4.接口隔离原则: 客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 5.迪米特法则还有一个更简单的定义:只与直接的朋友通信。其中,我们称出现成员...

    设计模式六大原则.doc

    设计模式六大原则是软件开发中不可或缺的指导方针,它们旨在提升代码的可维护性、可扩展性和可重用性。以下是对这些原则的详细解释: 1. 单一职责原则(Single Responsibility Principle, SRP): 这个原则强调一个...

    设计模式+六大原则pdf

    由孙玉山主编的“设计模式+六大原则”PDF,无疑是深入理解和掌握这些概念的宝贵资源。这本书不仅涵盖了全部的设计模式,还结合了软件体系结构的题目案例,以及源码分析,帮助读者将理论与实践相结合。 首先,我们来...

    JAVA 24种设计模式介绍与6大设计原则.pdf

    3. 依赖倒置原则(Dependency Inversion Principle, DIP):高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。 4. 接口隔离原则(Interface Segregation Principle, ISP...

    GOF的23种设计模式,及设计模式的六大原则

    设计模式的六大原则: 1. **开闭原则**:对扩展开放,对修改关闭,意味着在保持软件原有功能的基础上,可以方便地扩展新功能。 2. **里氏代换原则**:子类必须能够替换掉它们的基类,保证软件组件的可替换性,确保...

    23种 设计模式---面向对象的基本原则

    5. 依赖倒置原则(Dependency Inversion Principle, DIP):高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象。抽象不应该依赖于具体实现,而具体实现应该依赖于抽象。 接下来,我们来看看23种设计模式...

    设计模式6大原则.doc

    设计模式六大原则:单一职责模式、开闭原则、接口隔离原则、里氏替换原则、依赖倒置原则、迪米特法则

    设计模式与设计原则.pdf

    本文件《设计模式与设计原则.pdf》中,将详细地探讨设计模式以及与之相关的六大设计原则。 首先,设计模式主要分为三类: 1. 创建型模式(Creational patterns):这些模式提供了一种在创建对象的同时隐藏创建逻辑...

    设计模式和原则(很实用)

    3. **依赖倒置原则**:高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。 4. **接口隔离原则**:客户端不应该被迫依赖它不需要的接口,应该将接口拆分为更...

    24种设计模式介绍与6大设计原则

    六大设计原则包括: 1. 单一职责原则(Single Responsibility Principle, SRP):一个类应该仅有一个引起它变化的原因。 2. 里氏替换原则(Liskov Substitution Principle, LSP):子类应该能够替换掉它们的基类。...

    JAVA设计模式的六大原则

    ### JAVA设计模式的六大原则 #### 一、开闭原则(Open-Close Principle) **定义:** 开闭原则强调的是软件实体(类、模块、函数等)应该是可扩展的但不可修改的,即软件实体应该对扩展开放,对修改关闭。 **实践...

    Java23种设计模式6大原则

    六大设计原则是设计模式的基础,包括单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则和开闭原则。单一职责原则确保类只做一件事情,提高代码可读性和可维护性;里氏替换原则允许子类替换父类而...

    设计模式6大原则.zip

    在这个案例中,它可能提到了如何阅读和理解《Spring源码深度解析.pdf》中的内容,或者对设计模式六大原则的进一步说明和应用指导。 总之,设计模式六大原则是软件设计的核心思想,它们为构建高质量、可维护的软件...

Global site tag (gtag.js) - Google Analytics