【转】理解依赖注入(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声明而 ...
随机推荐
- 分治法(一)(zt)
这篇文章将讨论: 1) 分治策略的思想和理论 2) 几个分治策略的例子:合并排序,快速排序,折半查找,二叉遍历树及其相关特性. 说明:这几个例子在前面都写过了,这里又拿出来,从算法设计的策略的角度把它 ...
- 适配iOS9遇到的一些问题_Scheme白名单_ Bitcode及解决办法
升级Xcode7 运行项目发现报错如下: 1.Scheme白名单问题 -canOpenURL: failed for URL: “weixin://app/wxdaae92a9cfe5d54c/” - ...
- WPF 之 窗口间传参数
有如下几种方式: 1) 声明个全局变量,就是App.xaml里面声明:在所有窗体里面都可以引用 Application.Current.Properties["ArgumentName&qu ...
- 下拉选择框加listview删除
package com.downselect; import java.util.ArrayList; import android.R.array; import android.app.Activ ...
- 如何利用OCS存取PHP session全局变量
如何利用OCS存取PHP session全局变量 阿里云技术团队:余汶龙 一.场景介绍 用户在利用PHP搭建网站时,会把一些信息存放在$_SESSION全局变量里,可以很方便的存取.在PHP的in ...
- 【Mood-18】github 使用指南
windows下使用教程: http://www.cnblogs.com/dongdong230/p/4211221.html repository not found error问题解决(需确定gi ...
- Jqeury获取table当前行与指定列
今天遇到了一个Jqeury获取table当前行与指定列的问题: 大概的实现要求是一个页面中,上面有几个input输入框,下面有一个table,当在输入框中输入内容的时候,点击添加按钮的时候,在下面ta ...
- Json格式理解
json格式中共有三个重要符号"[","{",":" 中括号和花括号的唯一区别就是:中括号不需要key,花括号必须有key
- Shell学习笔记 - 环境变量配置文件
一.source命令 功能:在当前bash环境下读取并执行配置文件中的命令 1. 命令格式 source 配置文件 或 . 配置文件 2. 命令示例 [root@localhost ~]# sou ...
- C# 文件相关操作
百度搜的,下面这个写的挺全的. FROM Pegasus923 http://www.cnblogs.com/pegasus923/archive/2011/01/26/1944838.html ...