理解:

依赖倒置原则(DIP)主程序要依赖于抽象接口,不要依赖于具体实现。高层模块不应该依赖底层模块,两个都应该以来抽象。抽象不应该依赖细节,细节应该依赖抽象。(具体看我上一篇贴子

依赖倒置原则是六大设计原则中的一种,它的大致意思是所有模块都应该依赖于抽象,而不是直接依赖于另一个模块。依赖倒置原则仅仅只是一个原则而已,它只是告诉了你程序应该要变成什么样子(模块之间依赖抽象),而并没有具体告诉你应该怎么做。就像是在学校,老师告诉你教室要干净,不要有垃圾,而具体打扫垃圾的动作老师却并没有告诉你,你可以选择用扫把打扫,也可以选择用手捡,但是最终教室要干净(当然,你也可以不遵守)。

控制反转(IoC)就是遵循了依赖倒置原则的一个思想。

什么是控制?控制就是对对象进行创建、操作、销毁。

什么是“反转”(叫“转移”更为贴切)?“反转”的意思就是将“控制”的操作交由外部来处理,自己只管用,只管要,其他的都不管。

为什么说控制反转遵循了依赖倒置原则?虽然A模块需要B模块,但是A模块中并不是声明了B模块对象的引用,而是声明了对IB(B模块抽象)的引用,A模块真正需要的是实现了IB抽象的子类,所以A模块并不依赖于B模块,而是依赖于IB抽象。

控制反转的大意为:如果模块A需要模块B,模块A中并不是直接控制创建模块B,而是从外部控制如何创建。例如我们将创建何种对象的控制权交由配置文件控制,然后根据配置文件中的信息(程序集+类型),通过反射来获取对象,而不是直接new对象,这也是控制反转的一种体现。

IoC容器会连接程序中的所有模块,模块将所需对象的控制权都交由IoC容器控制,IoC容器会根据用户配置的信息将各个模块所需要的对象事先创建完成,然后IoC容器可以通过依赖注入(DI)的方式为模块注入所需对象(还有依赖查找(DL)),依赖注入就是一种具体实现的手段。

依赖倒置原则、控制反转和依赖注入并不是为程序带来新的功能,而是使得程序中模块的耦合性降低,提高每个模块的复用性。

举个栗子:

就拿生活中最常见的自助取款机来说一下,首先我们要拥有一张银行卡,例如建设银行的银行卡CCBCard类(设计的一些属性可能不太合理,不过重要的是了解思想)

//建行银行卡
public class CCBCard
{
//银行卡中的钱
public decimal Money { get; set; } //银行卡名字
public String Name { get; set; } public CCBCard(decimal money,String name)
{
this.Money = money;
this.Name = name;
}
}

然后我们来创建一个ATM自动取款机类,该取款机拥有取钱和存钱的功能

ATM机1.0

//自动取款机
public class ATM
{
//建行银行卡
public CCBCard Card = new CCBCard(1000,"建行卡"); //取钱
public void SubMoney(decimal money)
{
//判断余额是否足够
if (Card.Money >= money)
{
//取钱
this.Card.Money -= money;
Console.WriteLine($"取钱成功,余额{Card.Money}");
}
else {
Console.WriteLine("余额不足");
}
} //存钱
public void AddMoney(decimal money)
{
//存钱
this.Card.Money += money;
}
}

因为这个例子是生活中非常常见的,所以大家肯定一眼就看出了不妥

此时的ATM机可是说是个非常“睿智”的ATM机了,我去取钱,而ATM机却自带了一张建行银行卡,与其说是个ATM机,倒不如说只能对一个CCBCard建行卡进行存取的机器。此时ATM类完全依赖于CCBCard对象,而且CCBCard对象也是由ATM类创建的,如果CCBCard修改了,或者要换其他的卡,ATM机还要做出修改。

所以接下来我们应该将这不好的两点改掉:

1、ATM机只能读取单一的CCBCard卡(ATM控制CCBCard对象的创建)

2、ATM只能读取CCBCard类型的卡(ATM完全依赖于CCBCard对象)

先来解决第一点,接下来我们改进一下,为ATM机增加构造函数,通过构造函数传递CCBCard对象,使得ATM机可以操作其他建行卡:

ATM机2.1:

增加构造函数,两个方法不用变

//建行银行卡
public CCBCard Card; //构造函数传入CCBCard对象
public ATM(CCBCard card)
{
this.Card = card;
}

使用:

//银行卡
CCBCard card = new CCBCard(1000,"建行卡");
//ATM
ATM atm = new ATM(card);
//取钱
atm.SubMoney();

然后来解决第二个问题,只能存取建行卡:

此时就需要用到依赖倒置原则,让ATM类依赖于CCBCard抽象,而不是具体的实现。如果我们想存取其他银行卡里面的钱,必须为所有的银行卡抽象出一个接口,然后让所有银行卡子类都实现这个接口。

//银行卡接口
public interface ICard
{
string Name { get; set; }
decimal Money { get; set; }
}

建行卡实现该接口:

//建行银行卡
public class CCBCard:ICard
{
//银行卡中的钱
public decimal Money { get; set; } //银行卡名字
public String Name { get; set; } public CCBCard(decimal money,String name)
{
this.Money = money;
this.Name = name;
}
}

使得ATM机依赖于ICard接口(修改了Card属性和构造函数),而且ATM机并不控制ICard的子类,而是将控制权交由调用者。这一切才合情合理啊,无论用户插入什么卡,该ATM机都能进行存取。这就是控制反转,而通过构造函数传入的ICard对象则是通过依赖注入的方式注入对象。

//建行银行卡
public ICard Card; //构造函数传入ICard对象(依赖注入)
public ATM(ICard card)
{
this.Card = card;
}

依赖注入还有其他两种:通过接口和属性注入

//属性注入
public ICard Card { get; set; }
//接口注入
//该方法实现了接口
public void Inject(ICard card)
{
this.Card = card;
}

而接口注入就是通过方法注入,此种方式会增加不必要的接口,现在基本不使用,大多为构造函数注入。

新添加一个ICBC(工商银行)卡进行测试

//工商银行卡
public class ICBCCard : ICard
{
public string Name { get; set; }
public decimal Money { get; set; }
}

测试:

//建设银行卡
CCBCard bcard = new CCBCard(, "CCB");
//工商银行卡
ICBCCard ccard = new ICBCCard()
{
Money = ,
Name = "ICBC"
}; //ATM
ATM atm1 = new ATM(bcard);
ATM atm2 = new ATM(ccard);
//取钱
atm1.SubMoney();

IoC容器就是专门为ATM机这种模块服务的,它就像是一个大齿轮一样,连接所有小齿轮(模块),它运转,整个程序便运转,如果有些模块可能需要用到其他模块中的对象,它们并不会直接依赖,而是全都由IoC容器控制。

虽然互相需要,但是互不依赖,IoC容器会事先将ICard子类创建好,然后通过依赖注入注入到ATM机中(Unity、Spring.NET等框架都是封装完善的IoC容器),ATM机只管接收,只管索取。ATM机是不对子类进行创建的,控制权在用户手里,由用户控制ATM机操作何种银行卡,就像你去取钱一样,你插入什么卡自助取款机都可以取钱,这看起来是多么平常的一件事?很多看起来高大上的思想,都是从需求演变过来的,然后由前人一点点探索研究总结出来。

至此ATM机已经完成了,可能因为ATM机太常见了,所以我所说的一切你都可以想到(换卡,换不同银行的银行卡),就像是在说废话,如果你都理解了,那么根据ATM机,你应该仔细的思索一下,你所设计的类和模块满不满足像ATM机一样的“功能”?

依赖倒置原则(DIP)、控制反转(IoC)、依赖注入(DI)(C#)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. 依赖倒置原则(DIP)

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

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

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

  9. spring(3)------控制反转(IOC)/依赖注入(DI)

    一.spring核心概念理解 控制反转: 控制反转即IoC (Inversion of Control).它把传统上由程序代码直接操控的对象的调用权交给容器.通过容器来实现对象组件的装配和管理. 所谓 ...

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

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

随机推荐

  1. 【pip】brew install pip 问题

    Mac 下用 brew install pip 命令安装 pip 时报错: Error: No available formula with the name "pip" Home ...

  2. Pyenv虚拟环境的创建(虚拟机)

    创建pyenv虚拟环境 sudo yum install openssl* 安装其所需要的库文件 git clone https://github.com/yyuu/pyenv.git ~/.pyen ...

  3. Drawable与 Bitmap 转换总结

    极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android Drawable 使用方法详解请看上篇文章. Drawable 使用方法详解 本篇 ...

  4. [Spring cloud 一步步实现广告系统] 14. 全量索引代码实现

    上一节我们实现了索引基本操作的类以及索引缓存工具类,本小节我们开始实现加载全量索引数据,在加载全量索引数据之前,我们需要先将数据库中的表数据导出到一份文件中.Let's code. 1.首先定义一个常 ...

  5. 观书有感(摘自12期CSDN)

    CSDN要闻 Visual Studio 将登陆Mac平台 在11月的Connect()上,微软正式发布了Visual Studio For Max预览版,这是微软这一编程工具首次进入苹果平台.Vis ...

  6. JS判断字符串长度,结合element el-input el-form 表单验证(英文占1个字符,中文汉字占2个字符)

    首先看看判断字符串长度的几种方法(英文占1个字符,中文汉字占2个字符) 方法一: function strlen(str) { var len = 0; for (var i = 0; i < ...

  7. 【openmp】for循环的break问题

    问题描述:在用openmp并行化处理for循环的时候,便无法在for循环中用break语句,那么我们如何实现这样的机制呢?在stackoverflow上看到一个不错的回答总结一下. volatile ...

  8. Spring系列(四):Spring AOP详解

    一.AOP是什么 AOP(面向切面编程),可以说是一种编程思想,其中的Spring AOP和AspectJ都是现实了这种编程思想.相对OOP(面向过程编程)来说,提供了另外一种编程方式,对于OOP过程 ...

  9. Python 參考網站

    Python 3 Readiness : http://py3readiness.org/ Python Speed Center : https://speed.python.org/ Python ...

  10. Android UI控件常用库汇总

    现在App的开发已经是非常成熟,涌现了一大批开源的工具.这些项目能够提高我们的搬砖效率.以下是一些在开发中比较常使用的控件和库. ListView WaveSwipeRefreshLayout 水滴效 ...