依赖注入(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 依赖注入与控制反转 依赖注入与控制反转是老生常谈的问题.一般面试也会面试到这种问题.网上很多很多这方面的资料,搜索出来一大堆 ...
随机推荐
- 【甘道夫】Ubuntu群集配置 - 免费登陆
引言 这是几年前写的文章,但一直以来该问题被反复问到.所以我决定将它又一次搬上屏幕. 正文 三个节点:masternode slavenode1 slavenode2 第一步:全部节点分别生 ...
- 批量执行SQL文件
原文:批量执行SQL文件 摘要:很多时候我们在做系统升级时需要将大量的.sql文件挨个执行,十分不方便.而且考虑到执行顺序和客服的操作方便性,能不能找到一种简单的方法来批量执行这些sql文件呢? 主要 ...
- STL在迭代的过程,删除指定的元素
直接在Code.在 Picture #include <iostream> #include <list> using namespace std; // STL在迭代的过程中 ...
- 基于jsoup的Java服务端http(s)代理程序-代理服务器Demo
亲爱的开发者朋友们,知道百度网址翻译么?他们为何能够翻译源网页呢,iframe可是不能跨域操作的哦,那么可以用代理实现.直接上代码: 本Demo基于MVC写的,灰常简单,copy过去,简单改改就可以用 ...
- mvc中动态给一个Model类的属性设置验证
原文:mvc中动态给一个Model类的属性设置验证 在mvc中有自带的验证机制,比如如果某个字段的类型是数字或者日期,那么用户在输入汉字或者英文字符时,那么编译器会自动验证并提示用户格式不正确,不过这 ...
- springbatch操作CSV文件
一.需求分析 使用Spring Batch对CSV文件进行读写操作: 读取一个含有四个字段的CSV文件(id, name, age, score), 对文件做简单的处理, 然后输出到还有一个csv文件 ...
- 日积月累系列之分页控件(js源码)
最近开发了一款分页控件,分享给大家. 主要功能和界面介绍 cform分页控件支持服务端分页.客户端分页.数据过滤.数据排序等功能. 源码介绍 cform-pager分页控件主要由三部分组成:css.s ...
- APACHE启动失败是SYSTEM对apache目录没权限导致
表现如下: Apache: 1.The Apache service named reported the following error:>>> (OS 5)拒绝访问. : htt ...
- JAVA学习课第五十三届 — IO流程(七)File打靶 & Properties设置
一个.锻炼 深度遍历目录 深度遍历非常自然而然想到递归,而递归就非常自然的想到事实上现的底层算法是栈 对指定文件夹下列出全部内容(包括子文件夹的内容) PS:建议不要遍历C盘 import java. ...
- OCP-1Z0-051-题目解析-第10题
10. View the Exhibit and examine the structure of the PROMOTIONS table. Each promotion has a duratio ...