IoC和DI的理解
1 概述
当我们想闭上眼睛想如何让我们的软件更加可用可维护时,我们总能想到一个词:松耦合。在这篇文章中,主要讲述了模块间存在的依赖关系,但这种依赖关系违背了依赖倒置原则。在这之后,我们将讨论一种解除软件依赖关系的设计模式——IoC,以及它的两种实现方法:依赖注入(DI)和服务定位。最后我们简单地列下当前流行的IoC容器工具。
目录
- 依赖
- 依赖倒置原则(DIP)
- 控制反转IoC:解除两个模块间的直接依赖关系
- 依赖注入(DI)
- 服务定位(Service Locator)
- IoC容器
2 依赖
当一个模块/类使用另一个模块/类,即存在了一种依赖关系。
aaarticlea/png;base64,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" alt="" />
示例场景:
在这里,我们使用销售系统中保存订单的场景。比如,我们当前的需求是将数据保存到SQL Server中。在这里我们只关注业务层与数据持久层之间的依赖关系。
示例v1:
public class SQLServerOrderDAL
{
public void Add()
{
Console.WriteLine("The order was added in into sql server database.");
}
} public class OrderManager
{
public void AddOrder()
{
SQLServerOrderDAL orderDAL = new SQLServerOrderDAL();
orderDAL.Add();
}
} class Program
{
static void Main(string[] args)
{
OrderManager orderManager = new OrderManager();
orderManager.AddOrder(); Console.ReadLine();
}
}
3 依赖倒置原则(DIP)
在这个时候,当公司的牛XX业务人员将这个销售系统又卖给了另一家公司,大家都HAPPY。 但是对方公司唯一希望数据保存到ORACLE,因为他们其它的软件已经购买了ORACLE授权,并且不想再购买SQL SERVER授权。即软件需要支持数据库更换,我们应该如何解决
依赖倒置原则(DIP)
高层模块不应依赖于低层模块,两者应该依赖于抽象。
抽象不不应该依赖于实现,实现应该依赖于抽象。
上述示例v1中,OrderManager依赖于OrderDAL. 即高层模块(OrderManager)直接依赖于实现(OrderDAL), 而不是依赖于抽象。下面我们为数据持久层添加一层抽象,让业务层和数据持久实现层都依赖于抽象。
示例v2:
public interface IOrderDAL
{
void Add();
} public class OracleOrderDAL:IOrderDAL
{
public void Add()
{
Console.WriteLine("The order was added in into oracle database.");
}
} public class SQLServerOrderDAL:IOrderDAL
{
public void Add()
{
Console.WriteLine("The order was added in into sql server database.");
}
} public class OrderManager
{
public void AddOrder()
{
IOrderDAL orderDAL = new OracleOrderDAL();
orderDAL.Add();
}
} class Program
{
static void Main(string[] args)
{
OrderManager orderManager = new OrderManager();
orderManager.AddOrder(); Console.ReadLine();
}
}
4 控制反转IoC
程序到这里,数据访问层已经添加一层抽象,即业务层和数据持久层都依赖于抽象。但是,注意这里,依然存在都依赖,即业务层依然要直接依赖于低层的数据持久实现层。当更换数据库时,会有很多这样的代码要更换。你知道我在说什么的..这还是太恶心…
文章到这里了,我们先说说控制反转——IoC(Inversion of Control), 网上关于IoC的解释很多,我比较喜欢这种http://www.cnblogs.com/liuhaorain/p/3747470.html:
它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模块的类中直接通过new来获取
在多数情况下,上面的解释已经够用了,更广义一些的解释我认为是:
相对于过程式编程中,代码按顺序一步步执行,控制反转强调的是,将控制权交出,让第三方来控制程序的执行。
即除了将对象创建的工作交给第三方(我们主要关心的,如依赖注入和服务定位),IoC应该还包括将流程的控制转交出去,如事件,Callback 委托,观察者模式,异步等
在接下来的文章中,我们主要讨论依赖注入和服务定位。
5 依赖注入(DI)
依赖注入DI——Dependence Injection, 是一种IoC的实现方式。即将依赖对象的创建和绑定工作转移到第三者(调用方)。即 如果A对象依赖于B或C对象,那么就将B或C对象的创建工作转到A对象的调用方去。在上面示例中,将OracleOrderDAL或SQLServerOrderDAL的创建工作和绑定到IOrderDAL的工作转移到OrderManager的调用方中去,即具体对象创建的选择权移交到更高层的调用方法中。
依赖注入又分构造函数注入,属性注入和接口注入。我认为接口注入并不好用,所以这里只做构造函数和属性注入的示例。
5.1 构造函数注入
就是通过构造函数,传递依赖项。在这里,通过OrderManager的构造函数传入SQLServerOrderDAL或OracleOrderDAL
示例v3
public class OrderManager
{
private IOrderDAL _orderDAL; public OrderManager(IOrderDAL orderDAL)
{
this._orderDAL = orderDAL;
} public void AddOrder()
{ this._orderDAL.Add();
}
} class Program
{
static void Main(string[] args)
{
IOrderDAL orderDAL = new SQLServerOrderDAL();
//IOrderDAL orderDAL = new OracleOrderDAL(); OrderManager orderManager = new OrderManager(orderDAL);
orderManager.AddOrder(); Console.ReadLine();
}
}
5.2 属性注入
即通过属性传入依赖项。在这里,能过OrderManager的OrderDA属性项,传入SQLServerOrderDAL或OracleOrderDAL
示例4
public class OrderManager
{
private IOrderDAL _orderDAL; public IOrderDAL OrderDAL
{
set { this._orderDAL = value; }
get { return this._orderDAL; }
} public void AddOrder()
{ this._orderDAL.Add();
}
} class Program
{
static void Main(string[] args)
{
IOrderDAL orderDAL = new SQLServerOrderDAL();
//IOrderDAL orderDAL = new OracleOrderDAL(); OrderManager orderManager = new OrderManager();
orderManager.OrderDAL = orderDAL;
orderManager.AddOrder(); Console.ReadLine();
}
}
6 服务定位(Service Locator)
服务定位SL——Service Locator, 也是一种IoC的实现方式。即将依赖对象的创建和绑定工作转移到第三者(另一个模块)。即 如果A对象依赖于B或C对象,那么就将B或C对象的创建工作转到F对象中去。在上面示例中,将OracleOrderDAL或SQLServerOrderDAL的创建工作和绑定到IOrderDAL的工作转移到Factory中去, 即具体对象的创建选择权移交给Factory中。
示例v5
public class Factory
{
public static IOrderDAL GetOrderDAL()
{
//string type = "SQLServer";
string type = "Oracle";
string assemblyName = string.Format("v5_{0}DAL",type);
string typeName = string.Format("{0}.{1}OrderDAL",assemblyName,type);
return (IOrderDAL)Assembly.Load(assemblyName).CreateInstance(typeName);
}
} public class OrderManager
{
public void AddOrder()
{
IOrderDAL orderDAL = Factory.GetOrderDAL();
orderDAL.Add();
}
} class Program
{
static void Main(string[] args)
{
OrderManager orderManager = new OrderManager();
orderManager.AddOrder(); Console.ReadLine();
}
}
7 IoC容器
下面是一些主流的IoC容器工具以供参考
1. Unity: http://unity.codeplex.com/
2. Ninject: http://www.ninject.org/
3. Autofac: http://code.google.com/p/autofac/
4. Spring.NET: http://www.springframework.net/
Unity示例v6
public class OrderManager
{
private IOrderDAL _orderDAL; public OrderManager(IOrderDAL orderDAL)
{
this._orderDAL = orderDAL;
} public void AddOrder()
{ this._orderDAL.Add();
}
} class Program
{ static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
//container.RegisterType<IOrderDAL, SQLServerOrderDAL>();
container.RegisterType<IOrderDAL, OracleOrderDAL>(); OrderManager orderManager = container.Resolve<OrderManager>();
orderManager.AddOrder(); Console.ReadLine();
}
}
上面是一些我关于IoC和DI的理解,如有不对的地方,欢迎提出讨论。
相关链接:
Inversion of Control Containers and the Dependency Injection pattern
Inversion of Control and Dependency Injection: Working with Windsor Container
Dependency Injection (DI) vs. Inversion of Control (IOC)
Inversion of Control – An Introduction with Examples in .NET
Understanding Inversion of Control, Dependency Injection and Service Locator
Dependency Inversion Principle, IoC Container, and Dependency Injection
Unity Container Introduced by MSDN
IoC和DI的理解的更多相关文章
- 浅谈ASP.NET Core中IOC与DI的理解和使用
说起IOC和DI,使用过ASP.NET Core的人对这两个概念一定不陌生,早前,自己也有尝试过去了解这两个东西,但是一直觉得有点很难去理解,总觉得对其还是模糊不清,所以,趁着今天有空,就去把两个概念 ...
- Spring 学习教程(一):浅谈对Spring IOC以及DI的理解
一.个人对IoC(控制反转)和DI(依赖注入)的理解我们平时在开发java web程序的时候,每个对象在需要使用它的合作对象时,自己都要将它要合作对象创建出来(比如 new 对象),这个合作对象是由自 ...
- 对Spring中IOC和DI的理解
前几篇讲了Spring中IOC和DI的用法,本篇应该放到三篇之前,但一直没有想到好的讲解方式,后参考https://blog.csdn.net/luoyepiaoxue2014/article/det ...
- 关于IOC和DI的理解
IOC:Inversion of Control 控制反转 DI:Dependency Injection 依赖注入 控制反转,从字面意思来看,就是控制权又被动变主动,最后又变回被动. 举个例子: 你 ...
- IoC与DI的理解
首先要分享的是Iteye的开涛这位技术牛人对Spring框架的IOC的理解,写得非常通俗易懂,以下内容全部来自原文,原文地址:http://jinnianshilongnian.iteye.com/b ...
- 重温IOC,DI的理解
IOC和DI其实它们是同一个概念的不同角度描述 IOC强调的是程序控制对象(创建销毁),变换成了容器来控制对象(创建销毁) DI:即IoC容器帮对象找相应的依赖对象通过反射注入 从Spring ...
- Spring框架IOC,DI概念理解
1.什么是框架? 框架是一种重复使用的解决方案,针对某个软件开发的问题提出的. Spring框架,它是一个大型的包含很多重复使用的某个领域的解决方案. Spring的理念:不要重复发明轮子. 2.Sp ...
- 谈谈对IOC及DI的理解与思考
一.前言 在实际的开发过程中,我们经常会遇到这样的情况,在进行调试分析问题的时候,经常需要记录日志信息,这时可以采用输出到控制台. 因此,我们通常会定义一个日志类,来实现输出日志. 定义一个生成验证的 ...
- 框架面试题:谈谈我对Spring IOC与DI的理解
IOC是一种叫做“控制反转”的设计思想. 1.较浅的层次——从名字上解析 “控制”就是指对 对象的创建.维护.销毁等生命周期的控制,这个过程一般是由我们的程序去主动控制的,如使用new关键字去创建一个 ...
随机推荐
- Java 多态——与C++的比较
学习了Java和C++之后,由于长期不使用C++,而java的基础知识掌握不牢,现在已经搞不清java多态了.现在先来谈谈java多态,稍后有时间再更新C++的多态,并进行比较~ 一. Java的多态 ...
- pycharm运行脚本为何不生成测试报告?
今日使用python+selenium编写自动化测试脚本并执行过程中,使用pycharm运行结果后发现脚本运行无报错,脚本中的操作也正常被执行,但就是没有生成测试报告. 为什么呢,为什么呢,生成测试报 ...
- seajs模块化开发
seajs是一个起辅助作用的库,所以它可以更方便开发,而它可以解决以下问题: 1.命名问题,就是冲突 2.性能问题,就是只要一个功能,但却使用一个大插件中的一个小功能,所以要手动拆分出这个功能 3.j ...
- Geometry Curve of OpenCascade BRep
Geometry Curve of OpenCascade BRep eryar@163.com 摘要Abstract:几何曲线是参数表示的曲线 ,在边界表示中其数据存在于BRep_TEdge中,BR ...
- dropdownlist同时绑定数据库和自定义内容
在有些时候,我们需要dropdownlist里面包含“全部”这个字段,但是数据库中不存在“全部”,只存在具体的分类项. 这种情况下就需要先把数据库的数据源绑定到dropdownlist中,然后再在后面 ...
- IIS负载均衡(转)
在大型Web应用系统中,由于请求的数据量过大以及并发的因素,导致Web系统会出现宕机的现象,解决这一类问题的方法我个人觉得主要在以下几个方面: 1.IIS 负载均衡. 2.数据库 负载均衡. 3.系统 ...
- 使用Ambari安装hadoop集群
最近需要做些spark的工作,所以弄了几台dell7500就这么准备开始搭建集群,之前用过几台更破的台式机搭建过一次,折腾了半个月之久,终于成功搭建,这次不想走老路,所以网上查了一下,发现一个神器AM ...
- Unity 3D制作2D游戏的几种方法
1.使用本身UGUI. 2.把摄像机的投影改为正交投影,不考虑Z轴. 3.使用Untiy自身的2D模式. 4.使用2D TooKit插件.
- Azure ARM (3) ARM支持的服务类型
<Windows Azure Platform 系列文章目录> 我们在使用ARM创建资源的时候,首先要确认哪些Azure服务,支持ARM模式. 具体内容,我们可以参考连接:https:// ...
- c# 游戏策划配置工具
该工具是提供策划配置excel数据,导出到mysql数据库,以及生成xml文件,和对应的xml解析实体类 实现了程序 excel 列名 ID =P 表示ID这列是唯一字段 =S=300 表示这列类型是 ...