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)的更多相关文章

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

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

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

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

  3. 依赖倒置原则DIP&控制反转IOC&依赖注入DI

    依赖倒置原则DIP是软件设计里一个重要的设计思想,它规定上层不依赖下层而是共同依赖抽象接口,通常可以是上层提供接口,然后下层实现接口,上下层之间通过接口完全透明交互.这样的好处,上层不会因依赖的下层修 ...

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

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

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

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

  6. 依赖倒置原则(DIP)

    什么是依赖倒置呢?简单地讲就是将依赖关系倒置为依赖接口,具体概念如下: 1.上层模块不应该依赖于下层模块,它们共同依赖于一个抽象(父类不能依赖子类,它们都要依赖于抽象类) 2.抽象不能依赖于具体,具体 ...

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

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

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

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

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

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

  10. 依赖倒置原则DIP(面向接口编程—OOD)

    含义: 1.高层模块不应该依赖底层模块,两者都应该依赖其抽象. 2.抽象不应该依赖细节. 3.细节应该依赖抽象. 底层模块:不可分割的原子逻辑. 高层模块: 原子逻辑的再组装. 抽象:接口或者抽象类, ...

随机推荐

  1. redux的源码解析

    一. redux出现的动机 1. Javascript 需要管理比任何时候都要多的state2. state 在什么时候,由于什么原因,如何变化已然不受控制.3. 来自前端开发领域的新需求4. 我们总 ...

  2. [CNBETA]Intel CPU底层漏洞事件完全详解:全球手机/电脑无一幸免[转帖]

    http://www.cnbeta.com/articles/tech/685897.htm 由Intel CPU漏洞问题衍生出来的安全事件已经波及全球几乎所有的手机.电脑.云计算产品,ARM确认 C ...

  3. panda迭代

    1.注意 - 不要尝试在迭代时修改任何对象.迭代是用于读取,迭代器返回原始对象(视图)的副本,因此更改将不会反映在原始对象上. 2.itertuples()方法将为DataFrame中的每一行返回一个 ...

  4. 无返回值的异步方法能否不用await

    1.无返回值的异步方法能否不用await? 如果你不需要等待加一的操作完成,那就可以直接执行后面的操作.那要看你的需求了,如果你后面的操作必须在加一的操作后执行,那就要await了 2.请问C#中如何 ...

  5. Bootstrap洼地

    前面的话 这是一个轻量.灵活的组件,它能延伸至整个浏览器视口来展示网站上的关键内容.本文将详细介绍Bootstrap洼地 概述 洼地(Well)样式的效果和巨幕jumbotron样式类似,不同点是we ...

  6. ansible系列7-mysql_user模块

    添加mysql的用户和权限.密码 新增mysql用户zhang,设置登录密码zhang,给予权限zabbix.*:ALL ansible dba -m mysql_user -a 'login_hos ...

  7. jdbc,mybatis,hibernate各自有优缺点以及区别

    JDBC: 我们平时使用jdbc进行编程,大致需要下面几个步骤: 1,使用jdbc编程需要连接数据库,注册驱动和数据库信息 2,操作Connection,打开Statement对象 3,通过State ...

  8. 【 Gym - 101138D 】Strange Queries (莫队算法)

    BUPT2017 wintertraining(15) #4B Gym - 101138D 题意 a数组大小为n.(1 ≤ n ≤ 50 000) (1 ≤ q ≤ 50 000)(1 ≤ ai ≤  ...

  9. Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用

    1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...

  10. 洛谷 P3962 [TJOI2013]数字根 解题报告

    P3962 [TJOI2013]数字根 题意 数字根:这个数字每一位的数字加起来求和,反复这个过程直到和小于10. 给出序列\(a\),询问区间\([l,r]\)连续的子区间里最大前5个不同的数字根, ...