03-依赖倒置原则(DIP)
1. 背景
类A是高层代码,类A直接依赖B,如果要将类A改为还要依赖C,则必须修改类A的代码来实现。在实际场景中,类A是高层,负责业务逻辑,类B和类C是低层模块,负责基本的原子操作,假如修改A,会给程序带来不必要的风险。
2. 定义
高层模块不直接依赖低层模块,二者都应该依赖其抽象(抽象类或接口),抽象不应该依赖细节,细节应该依赖抽象。
3. 解决方案
类A修改为依赖接口I,而类B和类C各自实现接口I,类A通过接口I间接的同类B和类C发生联系,这样就大大降低了类的A的修改几率。
4. 依赖倒置原则的核心
面向接口编程。
5. 依赖倒置原则基于一个事实
相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在.Net中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
6. 从框架搭建的角度来体会依赖倒置原则的好处
三层:数据库访问层、业务逻辑层、UI调用层。
1. 数据库访问层中有一个 MySqlHelp类,提供链接MySQL数据增删改查的方法。
2. 业务逻辑层有一个登录业务 CheckLogin(MySqlHelp mysql,string userName,string pwd)。
3. UI调用层要调用CheckLogin方法,这时候实例化一个MySqlHelp对象,传到CheckLogin方法中即可。
有一个天,要求支持oracle数据,所以 数据库访问层中增加了一个oracleHelper类,UI调用层按照常规实例化了一个oracleHelper对象,传到CheckLogin方法中,发现我的天!!!!CheckLogin竟然不支持oracleHelper对象,同时发现类似的 所有业务层的方法都不支持oracleHelper类,这个时候悲剧就发生了,如果全部改业务层的方法,基本上完蛋。
所以解决方案:依赖倒置原则,即面向接口编程。
1. 数据库访问层声明一个接口IHelper,里面有增删改查方法,MySqlHelp和oracleHelper都实现IHelper接口
2. 业务逻辑层有一个登录业务改为依赖接口IHelper, CheckLogin(IHelper iHelper,string userName,string pwd)
3. UI调用层要调用CheckLogin方法,想连哪个数据,就实例化哪个 eg IHelper iHelper=new MySqlHelp(); 或者 IHelper iHelper=new oracleHelper()
然后调用CheckLogin即可
这种解决方案还有一个好处:先把接口约束定义出来了,写MySqlHelp和oracleHelper的人和 业务逻辑层的人可以同时开发了,不必等数据库访问层写完后,再写业务逻辑了。
7. 以日常生活为线索的案例
一个母亲给儿子讲书上的故事,所以有一个mother类,一个book类。
public class mother
{
public void readStorey(book bk)
{
Console.WriteLine("妈妈开始讲故事");
Console.WriteLine(bk.GetContents());
} }
public class book
{
public string GetContents()
{
return "我是书上的故事";
}
}
public static void show()
{
//下面以一个更贴切的例子说明一下这个问题
//一位母亲给儿子讲书上的故事,有一个mother类 ,一个book类
mother mt = new mother();
book bk = new book();
mt.readStorey(bk); }

突然有一天,儿子要求妈妈给他将报纸上的故事,我的天,妈妈竟然不会讲。
解决方案:mother类中readStorey类不在直接依赖book类,而是依赖book和newpaper类共同实现的接口类。
public interface IGetContents
{
string GetContents();
}
public class NewBook:IGetContents
{
public string GetContents()
{
return "我是书上的内容";
}
}
public class NewsPaper:IGetContents
{
public string GetContents()
{
return "我是报纸上的内容";
}
}
public class mother
{
public void readStorey2(IGetContents bk)
{
Console.WriteLine("妈妈升级了,会依赖倒置原则了,开始讲故事");
Console.WriteLine(bk.GetContents());
}
}
public static void show()
{
//有一天,儿子要求妈妈给他讲报纸上的故事
//有一个NewsPaper类,发现妈妈竟然不会讲报纸上的故事
//所以下面重构一下代码: 新的NewBook类,NewsPaper,新的讲故事的方法readStorey2,新的接口IGetContents
IGetContents ig1 = new NewBook();
IGetContents ig2 = new NewsPaper();
mt.readStorey2(ig1);
mt.readStorey2(ig2); }

8. 个人感悟
低层模块尽量都要有抽象类或接口,或者两者都有。
变量的声明类型尽量是抽象类或接口。
使用继承时遵循里氏替换原则。
03-依赖倒置原则(DIP)的更多相关文章
- C#软件设计——小话设计模式原则之:依赖倒置原则DIP
前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做“全战”, ...
- 7.12 其他面向对象设计原则3: 依赖倒置原则DIP
其他面向对象设计原则3: 依赖倒置原则DIP The Dependency Inversion Principle7.1 依赖倒置原则DIP The Dependency Inversion Pr ...
- 依赖倒置原则DIP&控制反转IOC&依赖注入DI
依赖倒置原则DIP是软件设计里一个重要的设计思想,它规定上层不依赖下层而是共同依赖抽象接口,通常可以是上层提供接口,然后下层实现接口,上下层之间通过接口完全透明交互.这样的好处,上层不会因依赖的下层修 ...
- 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解
1.概述 所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模 ...
- 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解(转)
所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合 ...
- 依赖倒置原则(DIP)
什么是依赖倒置呢?简单地讲就是将依赖关系倒置为依赖接口,具体概念如下: 1.上层模块不应该依赖于下层模块,它们共同依赖于一个抽象(父类不能依赖子类,它们都要依赖于抽象类) 2.抽象不能依赖于具体,具体 ...
- 设计模式学习--面向对象的5条设计原则之依赖倒置原则--DIP
一.DIP简介(DIP--Dependency Inversion Principle): 1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象.2.抽象不应该依赖于细节,细节应该依赖于抽象. ...
- 深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP
前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第5篇,依赖倒置原则LSP(The Dependency Inversion Principle ). 英文原文:htt ...
- IOS设计模式的六大设计原则之依赖倒置原则(DIP,Dependence Inversion Principle)
定义 高层模块不应该依赖于低层模块,二者都应该依赖于抽象:抽象不应该依赖细节:细节应该依赖抽象. 定义解读 依赖倒置原则在程序编码中经常运用,其核心思想就是面向接口编程,高层模块不应该依赖低层模块(原 ...
- 依赖倒置原则DIP(面向接口编程—OOD)
含义: 1.高层模块不应该依赖底层模块,两者都应该依赖其抽象. 2.抽象不应该依赖细节. 3.细节应该依赖抽象. 底层模块:不可分割的原子逻辑. 高层模块: 原子逻辑的再组装. 抽象:接口或者抽象类, ...
随机推荐
- Docker安装指定版本
今天新增一个Docker服务器,Docker安装顺利,启动hello-world测试的时候却出现了问题: $ docker run hello-worldUnable to find image 'h ...
- php实现常驻进程 多进程监控
php都是通过crontabd定时脚本处理队列的,面试被问到php如何常驻进程进行处理队列,想了半天这样不知道是否是一种方式 <?php function logs(){ file_put_co ...
- C++拷贝构造函数的调用时机
一.拷贝构造函数调用的时机 当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式和初始化对象 1. 初始化对象 初始化对象是指,为对象分配内存后第一次向内存中填 ...
- Angular生成二维码
Installation - Angular 5+, Ionic NPM npm install angularx-qrcode --save Yarn yarn add angularx-qrcod ...
- 第八周PSP 新折线图和饼图 个人时间管理
1.PSP DATE START-TIME END-TIME EVENT DELTA TYPE 4.18 15.36 16.10 读构建执法 走神5min 29mi ...
- 线性代数的本质与几何意义 01. 向量是什么?(3blue1brown 咪博士 图文注解版)
向量是线性代数最基础.最基本的概念之一,要深入理解线性代数的本质,首先就要搞清楚向量到底是什么? 向量之所以让人迷糊,是因为我们在物理.数学,以及计算机等许多地方都见过它,但又没有彻底弄懂,以至于似是 ...
- jQuery 簡介
jQuery:是一個js庫,可以極大地簡化編程,“寫得少做得多”. jquery的作用: 挑選元素.操作屬性.事件函數.動畫和效果.ajax: jQuery庫:google和microsoft都支持, ...
- Nginx PRECONTENT try_files指令
L:61 try_fiels指令 syntax : try_files file ... uri;=code //可以是多个文件 context : server,location; locatio ...
- linux sed的一些技巧
sed -i '$a # This is a test' regular_express.txt 由於 $ 代表的是最后一行,而 a 的动作是新增,因此该文件最后新增『# This is a test ...
- BZOJ2557[Poi2011]Programming Contest——匈牙利算法+模拟费用流
题目描述 Bartie and his friends compete in the Team Programming Contest. There are n contestants on each ...