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

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

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

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

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

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

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

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

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

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

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

[java] view plaincopy
  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://www.mzph.cn/news/351376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jirasearch 2.0狗粮:使用Lucene查找我们的Jira问题

几年前,我首先构建并发布了Jirasearch ,它是用于薄型包装Lucene服务器的有趣的狗粮测试用例,以针对我们的Jira问题公开强大的搜索UI。 这很好地展示了Lucene的许多重要功能: 使用块联接查询来建模父文档(原始的Jira问…

Highcharts教程--把js代码从html中抽离出来,放到单独的一个js文件中。由html页面调用...

1.html页面写法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>第一个 Highcharts 图表</title><!-- 引入 jquery.js --><script src"static/jquery-3.3.1.min.js"><…

数据结构c语言版第16页,数据结构c语言版

数据结构c语言版[编辑]概述《数据结构C语言版》本书的前半部分从抽象数据类型的角度讨论各种基本类型的数据结构及其应用;后半部分主要讨论查找和排序的各种实现方法及综合分析比较出版信息作/译者&#xff1a;严蔚敏&#xff0c;吴伟民 出版社&#xff1a;清华大学出版社出版日…

C语言申请内存时堆栈大小限制

一直都有一个疑问&#xff0c;一个进程可以使用多大的内存空间&#xff0c;swap交换空间以及物理内存的大小&#xff0c;ulimit的stack size对进程的内存使用有怎样的限制&#xff1f;今天特亲自动手实验了一次&#xff0c;总结如下&#xff1a; 开辟一片内存空间有2种方式&…

微服务之数据同步Porter

Porter是一款数据同步中间件&#xff0c;主要用于解决同构/异构数据库之间的表级别数据同步问题。 背景 在微服务架构模式下深刻的影响了应用和数据库之间的关系&#xff0c;不像传统多个服务共享一个数据库&#xff0c;微服务架构下每个服务都要有自己的数据库。如果你想获得微…

C语言采用多文件的工程结构百度,C语言学习知识复习资料结构框架学习知识重点.doc...

C语言学习知识复习资料结构框架学习知识重点.doc .思维导图1C语言程序设计知识结构第一课 C语言程序设计基础思维导图2第一课 C语言程序设计基础本课主要知识点1.知识点C程序基础l C语言是一种结构化程序设计语言。三种基本结构顺序、选择、循环。例1(2010-09-11)以下关于结构化…

antlr_ANTLR –语义谓词

antlr用antlr解析简单的语法很简单 。 您要做的就是使用正则表达式描述您的语言&#xff0c;并让antlr生成词法分析器和解析器。 解析大型或复杂的语言有时会需要更多&#xff0c;因为仅使用正则表达式描述它们是困难的&#xff0c;甚至是不可能的。 语义谓词是在语法内部编写…

栈大小和内存分部问题

今天面试问了一个栈大小问题&#xff0c;问过两次内存的结构问题&#xff0c;都没有答好&#xff0c;这次要弄清楚才行。 栈大小是有默认值的&#xff0c;如果申请的临时变量太大的话就会超过栈大小&#xff0c;造成栈溢出。 编译期限制栈大小&#xff0c;和系统限制栈深度根本…

ssh登陆报错“WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!”的解决方法

解决方法&#xff1a;删除 ~/.ssh/known_hosts转载于:https://www.cnblogs.com/liangxc/p/10414123.html

android 动态修改菜单,如何在Android的“选项”菜单上更改MenuItem?

如何在Android的“选项”菜单上更改MenuItem&#xff1f;我的Activity上有一个选项菜单&#xff0c;带有mymenu.xml“开始”。 选择此3000128611611048489985后&#xff0c;我想更改菜单&#xff0c;使其包含MenuItem“停止”。 最后&#xff0c;当选择“停止”时&#xff0c;我…

Java性能监控:您应该了解的5个开源工具

鲜为人知但有用&#xff1a;开源应用程序性能监视的状态 对于任何应用程序来说&#xff0c;最重要的事情之一就是性能。 我们要确保用户获得他们能获得的最佳体验&#xff0c;并且要知道我们的应用已启动并正在运行。 这就是为什么我们大多数人至少使用一种监视工具的原因。 …

【BZOJ1069】【SCOI2007】—最大土地面积(凸包+旋转卡壳)

传送门 考虑枚举任意222个点&#xff0c;那么只需要枚举第二个点的时候旋转卡壳就可以O(n)O(n)O(n)得到最远点对了 #include<bits/stdc.h> using namespace std; inline int read(){char chgetchar();int res0,f1;while(!isdigit(ch)){if(ch-)f-f;chgetchar();}while(isd…

如何在vs2010中修改栈的大小

上次运行程序的时候提示栈溢出&#xff0c;oh,my god 程序栈空间不够用了&#xff0c;没关系&#xff0c;可以设置栈的大小&#xff0c;默认是1MB。 选择 项目->属性->链接器->系统->堆栈保留大小,然后输入你想要的栈大小即可。

android第三方登录appid,AndroidQQ第三方登录

集成QQ登录在lib导入该open_sdk_r5886_lite.jar包AndroidManifest.xmlandroid:name"com.tencent.tauth.AuthActivity"android:launchMode"singleTask"android:noHistory"true" >android:theme"android:style/Theme.Translucent.NoTitleB…

Java数组、集合的三种遍历方式(包懂)

1 for循环 for(int i 0;i<arr.length;i){System.out.print(arr[i]" "); } 2 foreach循环&#xff0c;这种方式结构简单&#xff0c;可以简化代码 for(int i:arr){System.out.print(arr[i]" "); } 3 迭代器遍历 对于数组而言&#xff0c;就没必要转换为…

你应当如何学习C++(以及编程)(rev#1)

你应当如何学习C(以及编程)(rev#1) By 刘未鹏(pongba) C的罗浮宫(http://blog.csdn.net/pongba) JavaScript是世界上最受误解的语言&#xff0c;其实C何尝不是。坊间流传的错误的C学习方法一抓就是一大把。我自己在学习C的过程中也走了许多弯路&#xff0c;浪费了不少时间。 为…

android 悬浮窗口和主界面同时显示,Android 悬浮窗口(及解决6.0以上无法显示问题)...

思路实现通过WindowManager添加一个View&#xff0c;创建一个系统顶级的窗口&#xff0c;实现悬浮窗口的效果。本篇思路&#xff0c;来源于郭霖大神的悬浮窗口教程。大致介绍WindowManager 类创建的对象&#xff1a;Context.getSystemService(Context.WINDOW_SERVICE)常用API:a…

谷歌guava_Google Guava BloomFilter

谷歌guava当Guava项目发布版本11.0时&#xff0c;新添加的功能之一是BloomFilter类。 BloomFilter是唯一的数据结构&#xff0c;用于指示元素是否包含在集合中。 使BloomFilter有趣的是&#xff0c;它将指示元素是否绝对不包含或可能包含在集合中。 永远不会出现假阴性的特性使…

CMDB学习之三数据采集

判断系统因为是公用的方法&#xff0c;所有要写基类方法使用&#xff0c;首先在插件中创建一个基类 将插件文件继承基类 思路是创建基类使用handler.cmd ,命令去获取系统信息&#xff0c;然后进行判断&#xff0c;然后去执行 磁盘 &#xff0c;cpu&#xff0c;网卡&#xff0c;…

linux下挂载iso镜像的方法

新建目录/mnt/cdrom 执行命令 mount /dev/cdrom /mnt/cdrom 12[rootocdp1 cdrom]# mount /dev/cdrom /mnt/cdrommount: /dev/sr0 写保护&#xff0c;将以只读方式挂载进入/mnt/cdrom文件夹下发现里面是空的&#xff0c;说明挂载失败。 现在很多发行版中&#xff0c;光驱都不是/…