依赖倒置原则(DIP)定义:

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

问题由来:

类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,

负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。

解决方案:

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

ps:

依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础

搭建起来的架构要稳定的多。抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定

好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

依赖倒置原则的核心思想是面向接口编程,用一个例子来说明面向接口编程比相对于面向实现编程好在什么地方。

举个生活中的例子, 我们每天下班, 可能为了方便亦或锻炼身体, 选择骑单车回家, 对于现在单车, 又有各种各样: mobike, ofo, 小蓝, 小鸣等等...

(用C#代码表达)  定义3个实现, 分别对应的是各种单车品牌。

 public class BlueGoGo
{
public void Go()
{
Console.WriteLine("骑的是小蓝单车");
}
} public class Ofo
{
public void Go()
{
Console.WriteLine("骑的是小黄单车");
}
} public class Mobike
{
public void Go()
{
Console.WriteLine("骑的是摩拜单车");
}
}

然后再定义一个骑行类(Ride)

//骑行类
public class Ride
{
//扫码小蓝骑车
public void ScanCodeByBlueGoGo()
{
BlueGoGo blue = new BlueGoGo();
blue.Go();
} //扫码摩拜单骑车
public void ScanCodeByMoBike()
{
Mobike mo = new Mobike();
mo.Go(); } //扫码小黄骑车
public void ScanCodeByOfo()
{
Ofo ofo = new Ofo();
ofo.Go();
}
}

现在看上去确实也没什么问题, 所以调用一下, 一切正常

仔细看看, 这个代码确实有问题, 针对上面所讲的依赖倒置原则

<类A直接依赖类B, 假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,

负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。>

正如例子中的 骑行类(Ride) 正是依赖BlueGoGo,MoBike,Ofo类, 如果现在 Ride类要新增一个小鸣单车, 则我们必须要修改Ride的代码,同是添加一个XiaoMing的类达到效果。

 //骑行类
public class Ride
{
//扫码小蓝骑车
public void ScanCodeByBlueGoGo()
{
BlueGoGo blue = new BlueGoGo();
blue.Go();
} //扫码摩拜单骑车
public void ScanCodeByMoBike()
{
Mobike mo = new Mobike();
mo.Go(); } //扫码小黄骑车
public void ScanCodeByOfo()
{
Ofo ofo = new Ofo();
ofo.Go();
} /*
* 该功能位新增的小鸣单车, 必须修改Ride类
*/
public void ScanCodeByXiaoMing()
{
XiaoMing xming = new XiaoMing();
xming.Go();
}
}

像MoBike, BlueGoGo, Ofo, XiaoMing 这些类, 他们都属于底层模块, 负责基本的骑车的动作,  按照依赖倒置的原则, 则不应该修改A, 否则如果在业务量很大的情况下, 则会给程序带来不必要的潜在风险。

用依赖导致的思想怎么去实现 新增小鸣单车而不对高层模块进行修改?

1.将单车的每个Go动作都抽象起来, 分别让他们去做各自的实现。

//修改位抽象的车类
public abstract class abstarctBike
{
public abstract void Go();
} public class BlueGoGo: abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是小蓝单车");
}
} public class Ofo : abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是小黄单车");
}
} public class Mobike : abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是摩拜单车");
}
} public class XiaoMing : abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是小明单车");
}
}

这时, 我们再把骑行类(Ride)进行改造, 将原有的ScanCodeXXX 都弃用, 用一个全新的ScanCode提供一个抽象类型。

//骑行类
public class Ride
{
//
public void ScanCode(abstarctBike bike)
{
bike.Go();
} /*
* 以下位之前弃用的模式
*/ //扫码小蓝骑车
public void ScanCodeByBlueGoGo()
{
BlueGoGo blue = new BlueGoGo();
blue.Go();
} //扫码摩拜单骑车
public void ScanCodeByMoBike()
{
Mobike mo = new Mobike();
mo.Go(); } //扫码小黄骑车
public void ScanCodeByOfo()
{
Ofo ofo = new Ofo();
ofo.Go();
} /*
* 该功能位新增的小鸣单车, 必须修改Ride类
*/
public void ScanCodeByXiaoMing()
{
XiaoMing xming = new XiaoMing();
xming.Go();
}
}

现在, 我们再调用, 只要指定给Ride对象ScanCode执行的类型就可以实现骑行动作。

这样修改后,无论以后怎样扩展单车类,都不需要再修改Ride类了。这只是一个简单的例子,实际情况中,代表高层模块的Ride类将负责完成主要的业务逻辑,

一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。

在实际编程中,我们一般需要做到如下3点:

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

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

设计模式六大原则(三):依赖倒置原则(Dependence Inversion Principle)的更多相关文章

  1. 依赖倒置(Dependence Inversion Principle)DIP

    关于抽象类和接口的区别,可以参考之前的文章~http://www.cnblogs.com/leestar54/p/4593173.html using System; using System.Col ...

  2. 7.12 其他面向对象设计原则3: 依赖倒置原则DIP

    其他面向对象设计原则3: 依赖倒置原则DIP  The Dependency Inversion Principle7.1 依赖倒置原则DIP The Dependency Inversion Pr ...

  3. IOS设计模式的六大设计原则之依赖倒置原则(DIP,Dependence Inversion Principle)

    定义 高层模块不应该依赖于低层模块,二者都应该依赖于抽象:抽象不应该依赖细节:细节应该依赖抽象. 定义解读 依赖倒置原则在程序编码中经常运用,其核心思想就是面向接口编程,高层模块不应该依赖低层模块(原 ...

  4. [设计模式]<<设计模式之禅>>关于依赖倒置原则

    依赖倒置原则(Dependence Inversion Principle,DIP)这个名字看着有点别扭,“依赖”还“倒置”,这到底是什么意思?依赖倒置原则的原始定义是 High level modu ...

  5. 设计模式学习--面向对象的5条设计原则之依赖倒置原则--DIP

    一.DIP简介(DIP--Dependency Inversion Principle): 1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象.2.抽象不应该依赖于细节,细节应该依赖于抽象.   ...

  6. Java设计模式(2:单一职责原则和依赖倒置原则详解)

    一.单一职责原则 不要存在多于一个导致类变更的原因.简单来说,就是一个Class/Interface/Method只负责一项职责. 这句话最为重要的就是这一段:一个Class/Interface/Me ...

  7. 最简单直接地理解Java软件设计原则之依赖倒置原则

    理论性知识 定义 依赖倒置原则,Dependence Inversion Principle (DIP) 高层模块不应该依赖低层模块.二者都应该依赖其抽象. 抽象不应该依赖细节,细节应该依赖抽象. 针 ...

  8. 深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP

    前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第5篇,依赖倒置原则LSP(The Dependency Inversion Principle ). 英文原文:htt ...

  9. 设计模式课程 设计模式精讲 3-4 依赖倒置原则讲解+coding

    1 课程讲解 1.1 定义 1.2 优点 1.3 细节描述 2 代码演练 2.0 代码展示优点 2.1 非面向接口编程 2.2 面向接口编程1 传参 2.3 面向接口编程2 构造函数 2.4 面向接口 ...

随机推荐

  1. SpringMVC 常见异常处理

    1.javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"request" ...

  2. mahout处理路透社语料步骤,转换成须要的格式

    首先下载路透社语料(百度就能够下载): 然后上传Linux 并解压到指定文件夹.Tips:此处我放在可 /usr/hadoop/mahout/reutersTest/reuters tar -zxvf ...

  3. bind DNS搭建笔记

    设置默认网关 偶尔会出现问题 route add default gw 192.168.0.1 .vim /etc/sysctl.conf 这里是重点 配置路由转发,路由开启等都要用到. # Cont ...

  4. POJ 1330 Nearest Common Ancestors 倍增算法的LCA

    POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节 ...

  5. [ Java ] [ Eclipse ] 导出/导入Eclipse的workspace配置(备份Eclipse配置)

    Export *.epf 文件 原文連結: http://www.cnblogs.com/52php/p/5677647.html

  6. ThinkPad X260 UEFI安装 win7 64位 方法

    ThinkPad X260   UEFI安装 win7 64位 方法 1.使用DG重新格式化硬盘,格式为GPT 2.使用CGI  安装 WIM文件 (image不知是否可以,下次测试) 3.改BIOS ...

  7. VS Code在本地进行调试和打开本地服务器

    进行本地调试 1.在扩展中搜索插件 Debugger for Chrome 进行安装.我已经进行了安装,就没有出现安装字样. 2.配置launch.json文件,根据步骤来.file就是你在浏览器中需 ...

  8. rpm2cpio---如何不安装但是获取rpm包中的文件

    如何不安装但是获取rpm包中的文件 使用工具rpm2cpio和cpio rpm2cpio xxx.rpm | cpio -idmv 参数i表示提取文件.v表示指示执行进程,d和make-directo ...

  9. HDU——T 3072 Intelligence System

    http://acm.hdu.edu.cn/showproblem.php?pid=3072 Time Limit: 2000/1000 MS (Java/Others)    Memory Limi ...

  10. jsapi微信支付v3版

    请看清楚你的微信支付是v2还是v3.在这里整理的是v3的,v2的同学请忽略! 前期准备须要用的是商户证书,用的是p12的.设置api密钥(在微信商户端中设置),还须要在微信公众号中设置jsapi授权文 ...