设计模式六大原则(3)——依赖倒置原则
定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
依赖倒置原则的核心思想是面向接口编程,我们依旧用一个例子来说明面向接口编程比相对于面向实现编程好在什么地方。场景是这样的,母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。代码如下:
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 }
运行结果:
妈妈开始讲故事
很久很久以前有一个阿拉伯的故事……
运行良好,假如有一天,需求变成这样:不是给书而是给一份报纸,让这位母亲讲一下报纸上的故事,报纸的代码如下:
1 class Newspaper{ 2 public String getContent(){ 3 return "林书豪38+7领导尼克斯击败湖人……"; 4 } 5 }
这位母亲却办不到,因为她居然不会读报纸上的故事,这太荒唐了,只是将书换成报纸,居然必须要修改Mother才能读。假如以后需求换成杂志呢?换成网页呢?还要不断地修改Mother,这显然不是好的设计。原因就是Mother与Book之间的耦合性太高了,必须降低他们之间的耦合度才行。
我们引入一个抽象的接口IReader。读物,只要是带字的都属于读物:
1 interface IReader{ 2 public String getContent(); 3 }
Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,他们各自都去实现IReader接口,这样就符合依赖倒置原则了,代码修改为:
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点:
- 低层模块尽量都要有抽象类或接口,或者两者都有。
- 变量的声明类型尽量是抽象类或接口。
- 使用继承时遵循里氏替换原则。
依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。
转自:http://blog.csdn.net/zhengzhb/article/details/7289269
转载于:https://www.cnblogs.com/zl1991/p/6283221.html
设计模式六大原则(3)——依赖倒置原则相关推荐
- 设计模式六大原则之里氏替换原则、依赖倒置原则详解
设计模式六大原则--里氏替换原则.依赖倒置原则详解 1.里氏代换原则(Liskov Substitution Principle) 概念 顾名思义,该原则用于经常发生替换的地方,在Java中指的是实现 ...
- 3.六大原则例子-- 依赖倒置原则(DIP)例子
设计模式六大原则例子-- 依赖倒置原则(DIP)例子 之前我们对设计模式的六大原则做了简单归纳,这篇博客是对依赖倒置原则进行的举例说明. 依赖倒置原则的意义 DIP是6大原则中最难以实现的原则,它是实 ...
- 手撕设计模式,如何理解依赖倒置原则和好莱坞原则
一.什么是依赖倒置原则 依赖倒置原则,就是从客户端代码调用框架代码,变成框架调用客户端代码.框架来定义接口,客户端来实现. (1)高层模块不应该依赖底层模块,二者都应该依赖抽象 (2)抽象不应该依赖细 ...
- 软件设计原则之里氏替换原则、依赖倒置原则
系列文章目录 软件设计原则之单一职责原则.开闭原则 软件设计原则之里氏替换原则.依赖倒置原则 软件设计原则之接口隔离原则.合成复用原则.迪米特原则 文章目录 系列文章目录 一.里氏替换原则 什么是里氏 ...
- 7.12 其他面向对象设计原则3: 依赖倒置原则DIP
其他面向对象设计原则3: 依赖倒置原则DIP The Dependency Inversion Principle 7.1 依赖倒置原则DIP The Dependency Inversion P ...
- 设计原则 单一职责原则、开放封闭原则、依赖倒置原则、里氏代换原则、迪米特法则
目录 1 单一职责原则 2 开放封闭原则 3 依赖倒置原则 4 里氏代换原则 5 迪米特法则 1 单一职责原则 比如:电脑内存坏了就应该更换内存,不应该更换CPU (内存负责内存.CPU负责CPU) ...
- 面向对象设计原则-03依赖倒置原则
面向对象设计原则-03依赖倒置原则 依赖倒置原则的定义 依赖倒置原则(Dependence Inversion Principle,DIP)是 Object Mentor 公司总裁罗伯特·马丁(Rob ...
- 设计模式六大原则之--依赖倒置原则(DIP)
1. 依赖倒置原则,(Dependence Inversion Principle, DIP ) 定义:High level modules should not depend upon low le ...
- 设计模式六大原则:依赖倒置原则、为什么、多例子、分析例子、总结
1. 依赖倒置原则的定义 高层模块不应该依赖低层模块,二者都应该依赖其抽象 抽象不应该依赖细节,细节应该依赖抽象 依赖倒转的中心思想是面向接口编程 依赖倒转原则是基于这样的设计理念: 相对于细节的多变 ...
- 设计模式原则之依赖倒置原则
所谓依赖倒置原则(Dependence Inversion Principle )就是要依赖于抽象,不要依赖于具体.简单的说就是对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合. ...
最新文章
- opencv 连通域笔记
- ida android sign加密,最右sign-v2签名算法追踪及逆向还原
- hadoop 2.7.3 java_java - Hadoop 2.7.3 Java运行时错误 - 找不到core-site.xml - 堆栈内存溢出...
- CUDA ERROR: device-side assert triggered at解决
- RMQ问题(区间求最值)
- 和后台如何对接_业务系统如何对接第三方服务?
- 第十四篇 元类编程(二)
- maven夹包引入的速度问题
- mysql身份证号性别_mysql中身份证号判断男女人数
- Creator Kit: Beginner Code Unity学习记录 (1)
- 黑金xlinix FPGA学习笔记(一)verilogHDL扫盲文-(2)
- 《重装系统后弹出对话框(无法打开这个应用(无法使用内置管理员账户打开xx,请使用其他账户登录,……))》
- Java经典算法题目(兔子题)及题目分析
- 天津大学大作业管理概论答案
- Java 形参和实参
- 【刷题】BZOJ 2754 [SCOI2012]喵星球上的点名
- 【Unity小游戏】一款类似“恐龙快打”的《横版街机格斗游戏》 该如何制作?| 一起来学习 顺便送源码
- MATLAB绘制柱状图
- debian时间同步_如何在Debian 10上设置时间同步
- Bugku:分析 抓到一只苍蝇
热门文章
- 外联接、自联接与联合
- dwc3 linux usb3.0 driver架构
- garmin USB: linux USB host驱动
- 房贷是不是越多越久越好?
- java 使用string_java中string怎么使用
- 485通信原理_上位机开发之单片机通信实践
- 不是有效的win32应用程序_杀毒软件有坑!三分之二的安卓杀毒软件的“主业”并不是杀毒...
- linux复制文件通信方式,Linux分布式文件拷贝
- js方式调用php_js如何调用php函数
- java web 线程数_Java Web应用调优线程池