依赖注入(IOC)
依赖注入(IOC)
背景介绍
在设计模式中,尤其是结构型模式很多时候解决的就是对象间的依赖关系,变依赖具体为依赖抽象。平时开发中如果发现客户程序依赖某个或某类对象,我们常常会对他们进行一次抽象,形成抽象的抽象类、接口,这样客户程序就可以摆脱所依赖的具体类型。
这个过程中有个环节被忽略了------谁来选择客户程序需要的满足抽象类型的具体类型呢?通过后面的介绍你会发现很多时候创建型模式可以比较优雅的解决这个问题,但另一个问题出现了,如果您设计的不是具体的业务逻辑,而是公共库或框架程序呢,这时候你是一个‘服务方’,不是你调用那些构造类型,而是它们把抽象类型传给你,怎么松散地把加工好的抽象类型传递给客户程序就是另一回事了。
这个情形也就是常说的“控制反转”,IOC:Inverse of Control;框架程序与抽象类型的调用关系就像常说的好莱坞规则:Don’t call me,I’ll call you
示例场景
客户程序需要一个提供System.DateTime类型当前系统时间的对象,然后根据需要仅仅把其中的年份部分提取出来,因此最初的代码如下:
public class TimeProvider
{
public DateTime CurrentDate { get { return DateTime.Now; } }
} public class Client
{
public int GetYear()
{
TimeProvider timeprovider = new TimeProvider();
return timeprovider.CurrentDate.Year;
}
}
后来某种原因,发现使用.NET Framework自带的日期类型精度不够,需要提供其他来源的TimeProvider,确保在不同精度要求的功能模块中使用不同的TimeProvider。这样问题集中在TimeProvider的变化会影响客户程序,但其实客户程序仅需要抽象地使用其获取当前时间的方法。为此,增加一个抽象接口ITimeProvider,改造后的示例如下:
public interface ITimeProvider
{
public DateTime CurrentDate { get ; }
}
public class TimeProvider:ITimeProvider
{
public DateTime CurrentDate { get { return DateTime.Now; } }
} public class Client
{
public int GetYear()
{
ITimeProvider timeprovider = new TimeProvider();
return timeprovider.CurrentDate.Year;
}
}
这样看上去客户程序后续处理全部依赖于抽象的ITimeProvider就可以了,那么问题是否解决了呢?没有,因为客户程序还要知道SystemTimeProvider的存在。因此,需要增加一个对象,由它选择某种方式把ITimeProvider实例传递给客户程序,这个对象被称为Assembler.
对于依赖注入而言,Assembler的作用很关键,因为它解决了客户程序(也就是注入类型)与待注入实体类型间的依赖关系,从此Client只需要依赖ITimeProvider和Assembler即可,它并不知道TimeProviderImpl的存在。
Assembler的职责如下:
- 知道每个具体的TimeProviderImpl的类型。
- 根据客户程序的需要,将对象ITimeProvider反馈给客户程序。
- 负责对TimeProviderImpl实例化。
下面是一个Assembler的示例实现:
public class Assembler
{
//保存“抽象类型/实体类型"对应关系的字典
static Dictionary<Type, Type> dictionary = new Dictionary<Type, Type>(); static Assembler()
{
//注册抽象类型需要使用的实体类型
//实际配置信息可以从外层机制获得,例如通过配置定义
dictionary.Add(typeof(ITimeProvider), typeof(SystemTimeProvider));
}
/// <summary>
/// 根据客户程序需要的抽象类型选择相应的实体类型,并返回类型的实例
/// </summary>
/// <param name="type"></param>
/// <returns>实体类型实例</returns>
public object Create(Type type)//主要用于非泛型方式调用
{
if ((type == null) || !dictionary.ContainsKey(type))
throw new NullReferenceException();
return Activator.CreateInstance(dictionary[type]);
} /// <summary>
///
/// </summary>
/// <typeparam name="T">抽象类型(抽象类/接口/或者某种基类)</typeparam>
/// <returns></returns>
public T Create<T>()//主要用于泛型方式调用
{
return (T)Create(typeof(T));
}
}
构造注入(Constructor)
构造注入方式又称“构造子注入”、“构造函数注入”,顾名思义,这种注入方式就是在构造函数的执行过程中,通过Assembler或其它机制把抽象类型作为参数传递给客户类型。这种方式虽然相对其它方式有些粗糙,而且仅在构造过程中通过“一锤子买卖”的方式设置好,但很多时候我们设计上正好就需要这种“一次性”的注入方式。
其实现方式如下:
//在构造函数中注入
public class Client
{
ITimeProvider timerprovider;
public Client(ITimeProvider timeProvider)
{
this.timerprovider = timeProvider;
}
}
UnitTest
[TestClass]
public class TestClent
{
[TestMethod]
public void TestMethod1()
{
ITimeProvider timeProvider =
(new Assembler()).Create<ITimeProvider>(); Assert.IsNotNull(timeProvider);//确认可以正常获得抽象类型实例
Client client = new Client(timeProvider);//在构造函数中注入
}
}
设置注入(Setter)
设值注入是通过属性方法赋值的办法实现的。相对于构造方式而言,设值注入给了客户类型后续修改的机会,它比较适合于客户类型实例存活时间较长的情景。
实现方式如下:
//通过Setter实现中注入
public class Client
{
public ITimeProvider TimeProvider { get; set; }
}
Unit Test
[TestClass]
public class TestClent
{
[TestMethod]
public void TestMethod1()
{
ITimeProvider timeProvider =
(new Assembler()).Create<ITimeProvider>(); Assert.IsNotNull(timeProvider);//确认可以正常获得抽象类型实例
Client client = timeProvider;//通过Setter实现注入
}
}
从C#语言发展看,设置注入方式更”Lamada化“,使用时可以根据现场环境需要动态装配,因此在新项目中我更倾向于使用设置注入。这个例子更时髦的写法如下:[TestClass]
public class TestClent
{
[TestMethod]
public void TestMethod1()
{
var clent = new Client()
{
TimeProvider = (new Assembler()).Create<ITimeProvider>()
};
}
}
依赖注入(IOC)的更多相关文章
- android使用篇(四) 注解依赖注入IOC实现绑定控件
在android使用篇(三) MVC模式中提到一个问题: 1) 视图层(View):一般採用XML文件进行界面的描写叙述,使用的时候能够很方便的引入,可是用xml编写了,又须要在Acitvity声明而 ...
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探
更新 1.如果看不懂本文,或者比较困难,先别着急问问题,我单写了一个关于依赖注入的小Demo,可以下载看看,多思考思考注入的原理: https://github.com/anjoy8/BlogArti ...
- Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探
本文梯子 本文3.0版本文章 更新 代码已上传Github+Gitee,文末有地址 零.今天完成的绿色部分 一.依赖注入的理解和思考 二.常见的IoC框架有哪些 1.Autofac+原生 2.三种注入 ...
- 关于依赖注入IOC/DI的感想
之前一直不明白依赖注入有什么好处,甚至觉得它是鸡肋,现在想想,当时真是可笑. 这个想法正如同说接口是没有用处一样. 当整个项目非常庞大,各个方法之间的调用非常复杂,那么,可以想象一下,假设说没有任何的 ...
- DI依赖注入/IOC控制反转
DI依赖注入# 啥都不说,直接上代码 <?php class UserController { private $user; function __construct(UserModel $us ...
- Spring控制反转与依赖注入(IOC、DI)
IOC: 反转控制 Inverse Of Control DI:依赖注入 Dependency Injection 目的:完成程序的解耦合 解释:在应用系统的开发过程中,有spring负责对象的创 ...
- TypeC一个微软开发的超简单.NET依赖注入/IoC容器
控制反转(IoC,Inversion of Control)是由Martin Fowler总结出来的一种设计模式,用来减少代码间的耦合.一般而言,控制反转分为依赖注入(Dependency Injec ...
- C# 一个初学者对 依赖注入 IOC 的理解( 含 Unity 的使用)
通过 人打电话 来谈谈自己对IOC的理解 版本1.0 public class Person { public AndroidPhone Phone { get; set; } public void ...
- 大话DI依赖注入+IOC控制反转(二) 之 浅析.Net Core中的DI与IOC
转发时请注明原创作者及地址,否则追究责任.原创:alunchen 在上一篇文章中,我们聊了很多关于定义的方面,比较孤燥,下面我们结合.Net Core聊一下依赖注入&控制反转. 三种对象生 ...
- 大话DI依赖注入+IOC控制反转(一) 之 定义
转发时请注明原创作者及地址,否则追究责任.原创:alunchen 依赖注入与控制反转 依赖注入与控制反转是老生常谈的问题.一般面试也会面试到这种问题.网上很多很多这方面的资料,搜索出来一大堆 ...
随机推荐
- centos 之7zip
首先,我得说几句,我第一次进行了实验. 压缩文件夹html rar压缩 成绩5.18M zip压缩 成绩5.06M 7z压缩 成绩870K 第一种,源代码编译安装 官网下载地址:http:/ ...
- veridata实验举例(2)验证表BONUS与表SALGRADE两节点同步情况
veridata实验举例(2)验证表BONUS与表SALGRADE两节点同步情况 续接前几篇文章: 1.GoldenGate配置(一)之单向复制配置 地址:点击打开链接 2.GoldenGate配置( ...
- 利用webBrowser获取框架内Html页面内容
原文:利用webBrowser获取框架内Html页面内容 利用webBrowser获取页面比较简单,MSDN下有示例,在这里不必多说. 可是一些 HTML 文档由“框架”构成,或可以存放它们自己独特 ...
- ASP.NET学习笔记2--自己写代码绑定Gridview
像以前一样,先写好自己的样式布局, 第二步,在数据库建立一个商品表 代码如下: CREATE TABLE [SHANGPING_INFO] ( [Shangping_Id] INT PRIMARY K ...
- 苹果新的编程语言 Swift 语言进阶(十二)--选项链
选项链是使用选项来查询和调用其属性.方法或下标的一个过程,假设选项包括一个值,则属性.方法.下标的查询和调用成功,否则,调用返回nil. 选项链能用在不论什么类型的选项来检查对其一个属性.方法.下标的 ...
- mysql更改数据文件夹步骤与错误(ERROR 2002 (HY000))处理方法
1,关闭mysql服务: service mysqld stop 2,创建新建的文件夹 mkdir -p data 3,把曾经的文件夹转移到新的数据文件夹 mv /var/lib/mysql/ /da ...
- addEventListener 与attachEvent
第一:简单的通用方法(IE && FF) window.onload = function(){ var oDiv = document.getElementById("J_ ...
- [连载]Java程序设计(04)---任务驱动的方法:工资结算系统
任务:或在公司,该公司将其分为三类人员:部门经理.销售员.在发工资的时候,部门经理拿固定月薪8000元.技术人员按每小时100元领取月薪.销售人员依照500元底薪加当月销售额的4%进行提成.设计并实现 ...
- JS判断字符串是否全为中文
//第一种代码(全为中文则返回"true",不全为中文则返回"false"): <script language="javascript&quo ...
- Floodlight controller 线程池模型
官方文档对于ThreadPool的描写叙述是:ThreadPool is a Floodlight module wrapper for a Java's ScheduledExecutor ...