【转】理解依赖注入(IOC)和学习Unity
IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection)。
作用:将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调用完全面向接口。当系统重构的时候,代码的改写量将大大减少。
理解依赖注入:
当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例。然而采用依赖注入的方式,创建被调用者的工作不再由调用者来完成,因此叫控制反转,创建被调用者的实例的工作由IOC容器来完成,然后注入调用者,因此也称为依赖注入。
举个有意思的例子(来源于互联网)
1.青梅竹马:很久很久以前,有个有钱的地主家的一闺女叫Lily,她老爸把她许配给县太爷的儿子Jimmy,属于指腹为婚,Lily非常喜欢kiss,但是只能kiss Jimmy
- public class Lily{
- public Jimmy jimmy;
- public Girl()
- {
- jimmy=new Jimmy();
- }
- public void Kiss()
- {
- jimmy.Kiss();
- }
- }
- public class Jimmy
- {
- public void Kiss()
- {
- Console.WriteLine("kissing");
- }
- }
这样导致Lily对Jimmy的依赖性非常强,紧耦合。
2.亲友介绍:经常Kiss同一个人令Lily有些厌恶了,她想尝试新人,于是与Jimmy分手了,通过亲朋好友(中间人)来介绍
- public class Lily{
- public Boy boy;
- public Girl()
- {
- boy=BoyFactory.createBoy();
- }
- public void Kiss()
- {
- boy.Kiss();
- }
- }
亲友介绍,固然是好。如果不满意,尽管另外换一个好了。但是,亲友BoyFactory经常是以Singleton的形式出现,不然就是,存在于Globals,无处不在,无处不能。实在是太繁琐了一点,不够灵活。我为什么一定要这个亲友掺和进来呢?为什么一定要付给她介绍费呢?万一最好的朋友爱上了我的男朋友呢?
3.父母包办:一切交给父母,自己不用非吹灰之力,Lily在家只Kiss
- public class Lily{
- public Boy boy;
- public Girl(Boy boy)
- {
- this.boy=boy;
- }
- public void Kiss()
- {
- this.boy.Kiss();
- }
- }
Well,这是对Girl最好的方法,只要想办法贿赂了Girl的父母,并把Boy交给他。那么我们就可以轻松的和Girl来Kiss了。看来几千年传统的父母之命还真是有用哦。至少Boy和Girl不用自己瞎忙乎了。这就是IOC,将对象的创建和获取提取到外部。由外部容器提供需要的组件。
在设计模式中我们应该还知道依赖倒转原则,应是面向接口编程而不是面向功能实现,好处是:多实现可以任意切换,我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话,还可以kiss可爱的kitten和慈祥的grandmother
好在.net中微软有一个轻量级的IoC框架Unity,支持构造器注入,属性注入,方法注入如下图所示
具体使用方法如下图所示
- using System;
- using Microsoft.Practices.Unity;
- namespace ConsoleApplication9
- {
- class Program
- {
- static void Main(string[] args)
- {
- //创建容器
- IUnityContainer container=new UnityContainer();
- //注册映射
- container.RegisterType<IKiss, Boy>();
- //得到Boy的实例
- var boy = container.Resolve<IKiss>();
- Lily lily = new Lily(boy);
- lily.kiss();
- }
- }
- public interface IKiss
- {
- void kiss();
- }
- public class Lily:IKiss
- {
- public IKiss boy;
- public Lily(IKiss boy)
- {
- this.boy=boy;
- }
- public void kiss()
- {
- boy.kiss();
- Console.WriteLine("lily kissing");
- }
- }
- public class Boy : IKiss
- {
- public void kiss()
- {
- Console.WriteLine("boy kissing");
- }
- }
- }
如果采用配置文件注册的话
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <configSections>
- <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
- </configSections>
- <unity>
- <containers>
- <container name="defaultContainer">
- <register type="命名空间.接口类型1,命名空间" mapTo="命名空间.实现类型1,命名空间" />
- <register type="命名空间.接口类型2,命名空间" mapTo="命名空间.实现类型2,命名空间" />
- </container>
- </containers>
- </unity>
- </configuration>
配置的后台代码:
- UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName)
- as UnityConfigurationSection;
- configuration.Configure(container, "defaultContainer");
可以通过方法ResolveAll来得到所有注册对象的实例:
var Instances = container.Resolve<IKiss>();
Martin Fowler在那篇著名的文章《Inversion of Control Containers and the Dependency Injection pattern》中将具体依赖注入划分为三种形式,即构造器注入、属性(设置)注入和接口注入,习惯将其划分为一种(类型)匹配和三种注入:
- 类型匹配(Type Matching):虽然我们通过接口(或者抽象类)来进行服务调用,但是服务本身还是实现在某个具体的服务类型中,这就需要某个类型注册机制来解决服务接口和服务类型之间的匹配关系;
- 构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;
- 属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;
- 方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。
我们创建一个控制台程序,定义如下几个接口(IA、IB、IC和ID)和它们各自的实现类(A、B、C、D)。在类型A中定义了3个属性B、C和D,其类型分别为接口IB、IC和ID。其中属性B在构在函数中被初始化,以为着它会以构造器注入的方式被初始化;属性C上应用了DependencyAttribute特性,意味着这是一个需要以属性注入方式被初始化的依赖属性;属性D则通过方法Initialize初始化,该方法上应用了特性InjectionMethodAttribute,意味着这是一个注入方法在A对象被IoC容器创建的时候会被自动调用。
- public interface IA { }
- public interface IB { }
- public interface IC { }
- public interface ID { }
- public class A : IA
- {
- public IB B { get; set; }
- [Dependency]
- public IC C { get; set; }
- public ID D { get; set; }
- public A(IB b)
- {
- this.B = b;
- }
- [InjectionMethod]
- public void Initalize(ID d)
- {
- this.D = d;
- }
- }
- public class B : IB { }
- public class C : IC { }
- public class D : ID { }
然后我们为该应用添加一个配置文件,并定义如下一段关于Unity的配置。这段配置定义了一个名称为defaultContainer的Unity容器,并在其中完成了上面定义的接口和对应实现类之间映射的类型匹配。
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <configSections>
- <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
- </configSections>
- <unity>
- <containers>
- <container name="defaultContainer">
- <register type="UnityDemo.IA,UnityDemo" mapTo="UnityDemo.A, UnityDemo"/>
- <register type="UnityDemo.IB,UnityDemo" mapTo="UnityDemo.B, UnityDemo"/>
- <register type="UnityDemo.IC,UnityDemo" mapTo="UnityDemo.C, UnityDemo"/>
- <register type="UnityDemo.ID,UnityDemo" mapTo="UnityDemo.D, UnityDemo"/>
- </container>
- </containers>
- </unity>
- </configuration>
最后在Main方法中创建一个代表IoC容器的UnityContainer对象,并加载配置信息对其进行初始化。然后调用它的泛型的Resolve方法创建一个实现了泛型接口IA的对象。最后将返回对象转变成类型A,并检验其B、C和D属性是否是空
- class Program
- {
- static void Main(string[] args)
- {
- UnityContainer container = new UnityContainer();
- UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
- configuration.Configure(container, "defaultContainer");
- A a = container.Resolve<IA>() as A;
- if (null!=a)
- {
- Console.WriteLine("a.B==null?{0}",a.B==null?"Yes":"No");
- Console.WriteLine("a.C==null?{0}", a.C == null ? "Yes" : "No");
- Console.WriteLine("a.D==null?{0}", a.D == null ? "Yes" : "No");
- }
- }
- }
从如下给出的执行结果我们可以得到这样的结论:通过Resolve<IA>方法返回的是一个类型为A的对象,该对象的三个属性被进行了有效的初始化。这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性B)、属性注入(属性C)和方法注入(属性D)
a.B == null ? No
a.C == null ? No
a.D == null ? No
【转】理解依赖注入(IOC)和学习Unity的更多相关文章
- 理解依赖注入(IOC)和学习Unity
资料1: IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection). 作用:将各层的对象以松耦合的方式组织在一 ...
- 学习Unity -- 理解依赖注入(IOC)三种方式依赖注入
IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection).作用:将各层的对象以松耦合的方式组织在一起,解耦,各 ...
- 从壹开始前后端分离【 .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.三种注入 ...
- 深度理解依赖注入(Dependence Injection)
前面的话:提到依赖注入,大家都会想到老马那篇经典的文章.其实,本文就是相当于对那篇文章的解读.所以,如果您对原文已经有了非常深刻的理解,完全不需要再看此文:但是,如果您和笔者一样,以前曾经看过,似乎看 ...
- [转]深度理解依赖注入(Dependence Injection)
http://www.cnblogs.com/xingyukun/archive/2007/10/20/931331.html 前面的话:提到依赖注入,大家都会想到老马那篇经典的文章.其实,本文就是相 ...
- 理解依赖注入 for Zend framework 2
依赖注入(Dependency Injection),也成为控制反转(Inversion of Control),一种设计模式,其目的是解除类之间的依赖关系. 假设我们需要举办一个Party,Part ...
- 理解依赖注入(DI - Dependency Injection)
系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Contro ...
- android使用篇(四) 注解依赖注入IOC实现绑定控件
在android使用篇(三) MVC模式中提到一个问题: 1) 视图层(View):一般採用XML文件进行界面的描写叙述,使用的时候能够很方便的引入,可是用xml编写了,又须要在Acitvity声明而 ...
随机推荐
- 快递鸟API接口调用代码示例(免费不限量)
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...
- Joynet示例:知乎爬虫(搜索关键字相关回答,并下载其中的---图(mei)片(nv))
先贴爬虫程序下载地址:http://pan.baidu.com/s/1c2lxl1e 下载解压后 可直接运行 其中的 run.bat:或者你手动打开命令行执行:Joynet examples\Spid ...
- [Java,MVC] Eclipse下搭建Spring MVC
转自:http://blog.csdn.net/blue_jjw/article/details/8752466 一.新建Dynamic Web Project 一个web工程最基本的,只看3个地方, ...
- js兼容性问题
javscript 浏览器兼容性问题: scrollTop = document.documentElement.scrollTop || document.body.scrollTop; scrol ...
- [经典算法] 字符串搜索Boyer-Moore
题目说明: 今日的一些高阶程式语言对于字串的处理支援越来越强大(例如Java.C#.Perl等),不过字串搜寻本身仍是个值得探讨的课题,在这边以Boyer- Moore法来说明如何进行字串说明,这个方 ...
- 常见的 HTTP错误代码大全
一些常见的状态码为: - 服务器成功返回网页 - 请求的网页不存在 - 服务不可用 详细分解: 1xx(临时响应) 表示临时响应并需要请求者继续执行操作的状态代码. 代码 说明 (继续) 请求者应当继 ...
- struts1.3设置编码三种方法
本文所写涉及的struts的版本是1.3x. 一.改写struts的ActionServlet. 重写process()方法: 配置相应的web.xml文件 三.通过Chain来处理: 使用cha ...
- PHP实现无级递归分类(ThinkPHP框架)
/** * 无级递归分类 * @param int $assortPid 要查询分类的父级id * @param mixed $tag 上下级分类之间的分隔符 * @return string $tr ...
- windows更新npm
今天遇到一个项目需要更新npm的版本,搜了一下如何更新npm的方法,有的人说直接重装node,npm版本就会是最新的,真是无力吐槽,要是每次更新都得这么麻烦还得了,我觉得一定有更好更简单的方法,最后果 ...
- hdu 4729 树链剖分
思路:这个树链剖分其实还是比较明显的.将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数.当A<=B时,就全部建新的管子. 对于A>B的情况比较 建一条 ...