.NET IoC模式依赖反转(DIP)、控制反转(Ioc)、依赖注入(DI)
依赖倒置原则(DIP)
依赖倒置(Dependency Inversion Principle,缩写DIP)是面向对象六大基本原则之一。他是指一种特定的的解耦形式,使得高层次的模块不依赖低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象.
该原则规定:
- 高层次的模块不应该依赖低层次模块,二者都应该依赖其抽象接口.
- 抽象接口不应该依赖于具体实现,而具体实现则应该依赖于抽象接口.
通过如下一个简单的示例,我们来看一下,我们通过一个简单地下单流程向我们的用户发送相关的短信或者邮件.
public SendingEmail
{
public void Send(string message){
//do something
}
}
public Ordering
{
SendingEmail _sendingEmail=null;
public void Order(string message){
//Order business operation
if(_sendingEmail == null)
{
_sendingEmail=new SendingEmail();
}
_sendingEmail.Send(message);
}
}
这样看我们的代码没问题,目前只要我们完成了订单操作那么,那么则会触发发送功能,但是他却违反了DIP,因为Ordering类依赖于SendingEmail类,而SendingEmail类不是抽象类,而是一个具体的类.那我们再来想一个如果这时候业务口的人过来向我们提出了一个新的需求,要求我们改为短信而不是Email,那么我们需要怎么改?
public class SendingSMS
{
public void Send(string message){
//do something
}
}
public Ordering
{
SendingEmail _sendingEmail=null;
SendingSMS _sendingSMS=null;
bool isSendingSMS=true;
public void Order(string message){
//Order business operation
if(isSendingSMS){
if(_sendingSMS == null)
{
_sendingSMS=new SendingSMS();
}
_sendingSMS.Send(message);
}else{
if(_sendingEmail == null)
{
_sendingEmail=new SendingEmail();
}
_sendingEmail.Send(message);
}
}
}
根据上述需求我们不得不创建更多的类,并且在Ordering类中声明他,最后我们还需要使用IF ELSE语句来决定使用SMS还是使用电子邮件.但是当我们有更多这种处理操作后,那么可能比现在还混乱,这就意味着我们必须在Ordering类中声明更多新的具体类的实例.
我们需要抽离出来一种方式,让高级模块去依赖于抽象,用它来代替我们实现类,该抽象将映射到实现类.
控制反转(IoC)
控制反转(Inversion of Control,缩写为IOC)是面向对象中的设计原则,他可以帮助我们使高层模块依赖于抽象,而不是底层模块的具体实现.换句话说,他有助于实现(依赖倒置原则——DIP).
public interface ICustomerCommunication
{
void Send(string message);
}
然后我们修改SendingEmail和SendingSMS类以从ICustomerCommunication接口继承.
public class SendingEmail:ICustomerCommunication
{
public void Send(string message){
//do something
}
}
public class SendingSMS:ICustomerCommunication
{
public void Send(string message){
//do something
}
}
我们再来修改一下Ordering类以使用该抽象接口
public Ordering
{
ICustomerCommunication _customerComm=null;
bool isSendingSMS=true;
public void Order(string message){
//Order business operation
if(isSendingSMS){
if(_customerComm == null)
{
_customerComm=new SendingSMS();
}
_customerComm.Send(message);
}else{
if(_customerComm == null)
{
_customerComm=new SendingEmail();
}
_customerComm.Send(message);
}
}
}
通过如上修改我们做的控制反转更符合DIP.现在我们的高级模块只需要依赖于抽象,而不用去依赖实现.
依赖注入(DI)
依赖注入(Depeondency Injection,缩写为DI)是实现控制反转的一种方式.常用的依赖注入方法有3种:
- 构造函数注入
- 方法注入
- 属性注入
虽然说通过上面代码我们实现了IoC,并且Ordering类依赖于ICustomerCommunication抽象,但我们仍然在Ordering类中使用了实现类,这使用我们无法在类于类之间完全解耦.
if(isSendingSMS){
if(_customerComm == null)
{
_customerComm=new SendingSMS();
}
_customerComm.Send(message);
}else{
if(_customerComm == null)
{
_customerComm=new SendingEmail();
}
_customerComm.Send(message);
}
那我们再来说说DI,DI主要帮助我们将实现注入到抽象的类(ICustomerCommunication接口)中.DI的主要减少类之间的耦合,并且将抽象和具体实现的绑定移除依赖类.
- 构造函数注入
通过构造函数注入我们将实现类的对象传递给依赖类的构造函数,并将其分配给这个接口.
public class Ordering
{
ICustomerCommunication _customerComm=null;
public Ordering(ICustomerCommunication customerComm){
_customerComm=customerComm;
}
public void Order(string message){
_customerComm.Send(message);
}
}
在上面的代码中,构造函数将采用实现类对象绑定到接口中.如果我们将SendingSMS的实现传递给这个类,我们要做的就是声明一个SendingSMS类的实例,然后将其传递给Ordering的构造函数,如下所示:
SendingSMS sendingSMS=new SendingSMS();
Ordering ordering=new Ordering(sendingSMS);
ordering.Order("msg");
- 方法注入
通过使用构造函数注入,我们将不得不在Ordering类的生存期内使用实现类的实例SendingSMS或SendingEmail类.现在如果要在每次调用该方法时传递实现类的实例,则必须使用方法注入.
public class Ordering
{
public void Order(ICustomerCommunication customerComm,string message){
_customerComm=customerComm;
_customerComm.Send(message);
}
}
调用方式如下所示
SendingSMS sendingSMS=new SendingSMS();
Ordering ordering=new Ordering(sendingSMS);
ordering.Order(sendingSMS,"msg");
- 属性注入
通过如上描述我们知道了构造函数注入方法在整个生命周期中使用依赖类,而方法注入是将我们的注入直接去限于该方法中,然后我们再去了解一下属性注入
public class Ordering
{
public ICustomerCommunication customerComm {get;set;}
public void Order(string message){
_customerComm.Send(message);
}
}
调用方式如下所示
SendingSMS sendingSMS=new SendingSMS();
Ordering ordering=new Ordering(sendingSMS);
ordering.customerComm=sendingSMS;
ordering.Order("msg");
其实构造函数注入是实现DI最常用的方法.如果需要在每个方法调用上传递不同的依赖关系,则可以使用方法注入属性注入的使用还是比较少的.
Reference
https://zh.wikipedia.org/wiki/控制反转
https://zh.wikipedia.org/zh-hans/依赖反转原则
.NET IoC模式依赖反转(DIP)、控制反转(Ioc)、依赖注入(DI)的更多相关文章
- java依赖的斗争:依赖倒置、控制反转和依赖注入
控制反转(Inversion Of Controller)的一个著名的同义原则是由Robert C.Martin提出的依赖倒置原则(Dependency Inversion Principle),它的 ...
- 依赖倒置原则DIP&控制反转IOC&依赖注入DI
依赖倒置原则DIP是软件设计里一个重要的设计思想,它规定上层不依赖下层而是共同依赖抽象接口,通常可以是上层提供接口,然后下层实现接口,上下层之间通过接口完全透明交互.这样的好处,上层不会因依赖的下层修 ...
- PHP依赖倒置和控制反转
判断代码的好坏,我们有自己的标准:高内聚,低耦合.为了解决这一问题,php中有许多优秀的设计模式,比如工厂模式,单例模式. 而在代码中体现出来的设计模式,就如依赖注入和控制反转. 那什么是依赖注入? ...
- IoC(Inversion of Control 控制反转)
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(Dependency Inject ...
- [.net 面向对象程序设计深入](26)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)
[.net 面向对象程序设计深入](26)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...
- [.net 面向对象程序设计深入](31)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)
[.net 面向对象程序设计深入](31)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...
- 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。
轻松学,浅析依赖倒置(DIP).控制反转(IOC)和依赖注入(DI) 2017年07月13日 22:04:39 frank909 阅读数:14269更多 所属专栏: Java 反射基础知识与实战 ...
- IoC模式(依赖、依赖倒置、依赖注入、控制反转)
1.依赖 依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖.如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它.下面看一个 ...
- 个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解
一.依赖倒置(Dependency Inversion Principle) 依赖倒置是面向对象设计领域的一种软件设计原则.(其他的设计原则还有:单一职责原则.开放封闭原则.里式替换原则.接口分离原则 ...
- 【转载】浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文地址 http://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
随机推荐
- 猜数字和飞机大战(Python零基础入门)
前言 最近有很多零基础初学者问我,有没有适合零基础学习案例,毕竟零基础入门的知识点是非常的枯燥乏味的,如果没有实现效果展示出来,感觉学习起来特别的累,今天就给大家介绍两个零基础入门的基础案例:猜数字游 ...
- Obtain The String CodeForces - 1295C binary_search+思维
妈耶,,,被B题卡到哭,C题一发就过了... 字符串问题.首先用vector记录每个字符出现的位置,然后对字符串t的每个字符,用二分查找函数查找,注意用upper_bound查找,对于字符i,首先用变 ...
- B - Fadi and LCM CodeForces - 1285C 质因子
题目大意很简单,给你一个整数X,让你求a和b,使得max(a,b)尽可能的小,然后打印a,b 题解:想到了质因子分解,也考虑到了暴力,但是觉得暴力的话会TLE,所以打算用贪心做,然后就一直Wa.... ...
- div3--C. Pipes
题目链接:https://codeforces.com/contest/1234/problem/C 题目大意:根据规则,判断是否可以从左上走到右下,1,2,3,4,5,6分别对应题干给的图片,所以1 ...
- 数据结构(C语言版)---栈
1.栈:仅在表尾进行插入和删除操作的线性表.后进先出LIFO. 1)表尾端(允许插入和删除的一端)为栈顶,表头端(不允许插入和删除的一端)为栈底. 2)入栈:插入元素的操作.出栈:删除栈顶元素 3)栈 ...
- jdbctemplate打印sql
在logback.xml里加入如下配置即可: <include resource="org/springframework/boot/logging/logback/base.xml& ...
- 谈谈MySQL的索引
目录 索引 前言 是什么 B树 B+树 B树和B+树结构上异同 有什么用 怎么用 索引 前言 总所周知,数据库查询是数据库的最主要功能之一.我们都希望查询数据的速度能尽可能的快.而支撑这一快速的背后就 ...
- 初识Cobalt Strike
简介 Cobalt Strike 一款以metasploit为基础的GUI的框架式渗透工具,集成了端口转发.服务扫描,自动化溢出,多模式端口监听,win exe木马生成,win dll木马生成,jav ...
- Mysql基础练习--实例
修改字段名:alter table 表名 change 旧字段名 新字段名 新数据类型;--- 主键 ------------------------------------------------- ...
- JDBC 中的事务和批处理 batch
JDBC事务处理: 事务处理一般在事务开始前把事务提交设置为false 所有DML语句执行完成后提交事务 demo: package com.xzlf.jdbc; import java.sql.Co ...