依赖注入(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 依赖注入与控制反转 依赖注入与控制反转是老生常谈的问题.一般面试也会面试到这种问题.网上很多很多这方面的资料,搜索出来一大堆 ...
随机推荐
- 【百度地图API】如何利用PhoneGap制作地图APP
原文:[百度地图API]如何利用PhoneGap制作地图APP 摘要:百度地图API是一套由javascript编写的地图程序接口,按说它应该运行在浏览器上.现在,只要利用PhoneGap,我们就能开 ...
- 如何完成Nexus 9上电后激活过程
所述被激活,因为它是Nexus 9经过努力获得启动OTA最新更新包,而且因为Google关闭一堵墙.原因无法下载更新包. 因为是第一次开机,它不能被设置usb debugging, 无法adb去杀死w ...
- Win7搭建NodeJs开发环境
Win7搭建NodeJs开发环境以及HelloWorld展示—图解 Windows 7系统下搭建NodeJs开发环境(NodeJs+WebStrom)以及Hello World!展示,大体思路如下:第 ...
- Spring之单元测试
引言 是否在程序运行时使用单元测试是衡量一个程序员素质的一个重要指标.使用单元测试既可以让我检查程序逻辑的正确性还可以让我们减少程序测试的BUG,便于调试可以提高我们写程序的效率.以前我们做单元测试的 ...
- leetcode 第42题 Multiply Strings
题目:Given two numbers represented as strings, return multiplication of the numbers as a string. Note: ...
- Android Fragement学习笔记(三)----PreferenceFragment使用
我相信每个人都Perference大家都比较熟悉,这就是我们常说的偏好,首选项设置,一些数据可以保存.例如,一些元件的,我们使用上次.希望下次启动后仍然生效,烦.一般这个时候我们便会使用perfere ...
- SQL面试题1
SQL面试题 Sql常用语法 下列语句部分是Mssql语句,不可以在access中使用. SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言 ...
- asp.net mvc使用validate.js验证 若name属性包含特殊字符则加上双引号即可
rules: { "Can.CName": { required: true, ...
- MVC Bootstrap极速开发框架
ASP.NET MVC Bootstrap极速开发框架 前言 每次新开发项目都要从头开始设计?有木有一个通用的快速开发框架?并且得是ASP.NET MVC And Bootstrap?数据库不要手工 ...
- 使用fixed制作浮动广告(注意:解决闪屏问题,但适用于高版本浏览器,低版本的浏览器不适用)
<script language="javascript" type="text/javascript"> //隐藏广告 function clos ...