依赖倒置原则(Dependence Inversion Priiciple,DIP)

介绍

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Detatils should depend upon abstractions.

翻译过来有是三个意思:

1.高层模块不应该依赖底层模块,两者都应该依赖其抽象。

2.抽象不应该依赖细节。

3.细节应该依赖抽象。

在Java中,表现就是:

1.模块间的依赖通过抽象发生,实现类之间不应该发生直接的依赖关机,其依赖关系应该是用过接口或者抽象类产生的;

2.接口或者抽象类不应该依赖实现类;

3.实现类应该依赖接口或者抽象类。

依赖倒置原则的设计理念是:相较于实习类具有多变性,抽象要稳定的多。框架的设计应该基于抽象,这样子,能提高项目的稳定性。

在框架中,抽象的作用是用来制定规范,具体的细节应该交给实现类。

应用实例

有一个司机类对象张三(zs),具有drive方法来驾驶汽车。

public class Dependence1 {
public static void main(String[] args) {
Driver zs = new Driver();
Benz benz = new Benz();
zs.drive(benz);
}
} class Driver {
public void drive(Benz benz) {
benz.run();
}
} class Benz {
public void run() {
System.out.println("奔驰汽车发动...");
}
} //经过艰苦奋斗,张三同志买了一辆宝马汽车
class BMW {
public void run() {
System.out.println("宝马汽车发动...");
}
}

目前为止,看上去很美好,正常的功能也实现了;但是,因为这个功能是基于具体的实现类Benz实现的,这就为后来的扩展带来了麻烦:比如张三同志艰苦奋斗,又买了一辆宝马(BMW),但是根据Driver类的drive方法,张三同志不能驾驶新买的宝马汽车。这就是很严重的逻辑了:只要是有了驾照,奔驰和宝马应该都能驾驶。

改进措施:

很明显,司机类中的drive方法不应该依赖于一种具体品牌的汽车,而因该是汽车的泛指。所以,新建两个接口:

IDriver和ICar,分别定义了司机和汽车的职能,汽车就是驾驶汽车。具体的代码如下:

public class Dependence2 {
public static void main(String[] args) {
IDriver zs = new Driver();
ICar benz = new Benz();
zs.drive(benz);
ICar bmw = new BMW();
zs.drive(bmw);
}
} interface ICar {
//是汽车都应该具备的功能
public void run();
} class Benz implements ICar {
@Override
public void run() {
System.out.println("奔驰汽车发动...");
}
} class BMW implements ICar {
@Override
public void run() {
System.out.println("宝马汽车发动...");
}
} interface IDriver {
//是司机就应该会开车,不管是什么车
public void drive(ICar iCar);
} class Driver implements IDriver {
@Override
public void drive(ICar iCar) {
iCar.run();
}
}

在demo中,类Dependence2 作为高层模块,它对底层模块的依赖建立在抽象上;司机张三的表面类型时IDriver,Benz和BMW的表面类型是ICar,这样做,在扩展业务逻辑(比如新增一辆汽车Mini)时,只需修改业务场景类(高层模块),对底层模块如Driver和Benz等没有影响。

依赖的三种形式

依赖的形式有三种:接口依赖、setter方法依赖和构造器依赖。具体介绍如下:

1.接口依赖

顾名思义,就是通过实现接口的方式注入依赖,代码详见上面的改进措施。

2.setter方法依赖

在抽象中定义setter方法,就是所谓的setter方法依赖。

demo如下:

interface IDriver {
//setter方式注入
public void setICar(ICar iCar); } class Driver implements IDriver {
private ICar iCar; @Override
public void setICar(ICar iCar) {
this.iCar = iCar;
} }

3.构造器依赖

这个也比较好理解,就是将ICar的具体类型,通过构造器传给Driver:

class Driver implements IDriver {
private ICar iCar; public Driver(ICar iCar) {
this.iCar =iCar;
}
}

注意事项和细节

在项目中,底层模块的类都应该有抽象类或者接口,或者两者都有;

变量的声明应该是抽象类型,有利于提高项目的稳定性;

任何类都不应该从具体类派生;

尽量不要重写积累的方法,要结合“里氏替换原则”使用。

DesignPattern系列__03依赖倒置原则的更多相关文章

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

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

  2. C#软件设计——小话设计模式原则之:依赖倒置原则DIP

    前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做“全战”, ...

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

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

  4. 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解

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

  5. 第2章 面向对象的设计原则(SOLID):3_依赖倒置原则(DIP)

    3. 依赖倒置原则(Dependence Inversion Principle,DIP) 3.1 定义 (1)要依赖抽象,不要依赖具体的实现类.简单的说就是对抽象(或接口)进行编程,不要依赖实现进行 ...

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

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

  7. 【设计模式六大原则3】依赖倒置原则(Dependence Inversion Principle)

      定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象:抽象不应该依赖细节:细节应该依赖抽象. 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成.这种场景下,类 ...

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

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

  9. ASP.NET 设计模式中依赖倒置原则

    依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象. B.抽象不应该依赖于具体,具体应该依赖于抽象. 依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于 ...

随机推荐

  1. python小方法 随笔记

    1. 元组和列表的接收 s1,s2 = [,] print(s1,s2) # 执行结果: 1 2 s3,s4 = (,) print(s3,s4)# 执行结果: 3 4 2. 变量值的交换 a = b ...

  2. MySQL索引的数据结构-B+树介绍

    目录 一.树 二.B+树 2.1 B+树性质 三.聚集索引和辅助索引 3.1 聚集索引 3.2 辅助索引 3.3 聚集索引和非聚集索引的区别 四.再看B+树 4.1 B+树的插入操作 4.2 B+树的 ...

  3. BZOJ 3990 排序

    [题目描述]: 小A有一个1~2N的排列A[1..2N],他希望将数组A从小到大排序.小A可以执行的操作有N种,每种操作最多可以执行一次.对于所有的i(1<=i<=N),第i种操作为:将序 ...

  4. 使Toast弹出不重叠的封装

    一.问题 在频繁弹出toast的时候,弹出后出现延迟重叠的现象. 二.解决 Toast通常由makeTextT()方法实例化,如何不想要toast弹出时重叠,那么只需在应用中保持一个Toast对象即可 ...

  5. 大规模SDN云计算数据中心组网的架构设计

    本文首先分析了在大规模SDN数据中心组网中遇到的问题.一方面Underlay底层组网规模受限于设备实际的转发能力和端口密度,单一Spine-leaf的Fabric架构无法满足大规模组网的需求:另一方面 ...

  6. 看看大神 Paul Graham 对如何学习编程的回答

    前言 我翻阅自己之前写的博客文章,发现在 2015 年我刚开始学习编程的时候,翻译了一段 Paul Graham 关于"How can I learn to program?"的回 ...

  7. wussUI v1.0.0小程序UI组件库 第一期开发已完成

    经过了两个月不到的开发时间,我们phonycode团队顺利的发布了小程序的UI组件库 wuss-ui 的第一个版本.目前大体预览如下 介绍 wussUI 现在有大概27个组件左右, 目前基础组件都有了 ...

  8. Java开发面试题汇总 -- 精选版(附答案)

    最近事情太多,没太时间写公众号.今天抽空再整理整理面试中的那点事吧,帮助那些正在找工作或想跳槽找工作的兄弟姐妹们. 前面我己写过多篇推文,相信关注此公众号的伙伴们已经了解掌握了不少.从目前流行的开发技 ...

  9. MyBatis从入门到精通:select用法进一步讲解

    selectAll:笔记 /* 定义接口方法的返回值的时候,必须注意查询SQL可能返回的结果数量.当 返回值最多只有一个结果的时候,可以将结果返回值定义为SysUser,此时 返回值类型为List&l ...

  10. Dock学习(一):容器介绍

    一.什么是容器 1.容器是一种轻量级.可移植.自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行.开发人员在自己的笔记本上创建并测试好的容器,无需任何修改就能够在生产系统的虚拟机.或物 ...