本篇幅主要介绍控制反转的一些概念,和如何使用Unity实现Ioc。在介绍的时候,会尽量结合代码来讲解一些概念。

1.什么是DI?

DI即控制反转,是将对具体实现类的依赖转变为对接口的依赖,这样在编程中,就可以发挥类的多态性。我们先假设一台印钞机,功能是打印钞票,根据使用的模板,可以印人民币(想到这里,我做梦都乐了)。具体实现如下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace IocWithUnity
{
/// <summary>
/// 印钞机
/// </summary>
public class CashMachine
{
public CashMachine() { } public void Print()
{
CNYCashTemplate template = new CNYCashTemplate(); string templateContent = template.GetTemplate(); System.Console.WriteLine(templateContent);
}
}
/// <summary>
/// 人民币钞票模板
/// </summary>
public class CNYCashTemplate
{
public CNYCashTemplate() { } public string GetTemplate()
{
return "这是人民币模板";
}
}
}

是不是很爽?可以印很多RMB了。哈哈哈哈!!!可是有一天,我们的机器要卖去美国,印美钞,怎么办,于是,我们加了一个美钞模板。代码如下:

/// <summary>
/// 美钞钞票模板
/// </summary>
public class USDCashTemplate
{
public USDCashTemplate() { } public string GetTemplate()
{
return "This is US Dollor.";
}
}

这下尴尬了,我们还得再建一个USDCashMachine。同样的代码,再写一遍。单是优秀的程序猿具有一个良好的特质--懒,所以我们打算改一下,成下面那样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace IocWithUnity
{
/// <summary>
/// 印钞机
/// </summary>
public class CashMachine
{
public CashMachine() { } public void Print(ICashTemplate template)
{
string templateContent = template.GetTemplate(); System.Console.WriteLine(templateContent);
}
}
/// <summary>
/// 印钞模块
/// </summary>
public interface ICashTemplate
{
/// <summary>
/// 获取钞票模板
/// </summary>
/// <returns></returns>
string GetTemplate();
} /// <summary>
/// 人民币钞票模板
/// </summary>
public class CNYCashTemplate : ICashTemplate
{
public CNYCashTemplate() { } public string GetTemplate()
{
return "这是人民币模板";
}
}
/// <summary>
/// 美钞钞票模板
/// </summary>
public class USDCashTemplate : ICashTemplate
{
public USDCashTemplate() { } public string GetTemplate()
{
return "This is US Dollor.";
}
}
}

我们在调用的时候就变成了

ICashTemplate template = new USDCashTemplate();
new CashMachine().Print(template);

这个时候,我们想印美钞,就放美钞的模板,想印人民币,就印人民币的模板,厉害了吧?

没错,这就是面向接口的依赖反转,我们的CashMachine从依赖CNYCashTemplate这个具体实现,变成了对ICashTemplate接口的依赖,在上面我们采用的是方法的注入,我们也可以用构造函数注入,用属性注入,思路都是一样的。这就是为什么我们一直强调

面向接口编程,因为面向接口编程可以增强代码结构的稳定性和可扩展性。

2.什么是Ioc?

上面我们的印钞机已经可以印各种钞票了。那么我们在实际开发当中,如果你进行了分层,想必应该是这样的:

Cash.Business---业务层
Cash.Templates---钞票模板实现
Cash.IContract--接口层

那么这三层的依赖关系应该是

作为一个有代码洁癖的猿,肯定是不想有那么多复杂的关系的。业界有一句著名的话怎么说来着,没有加一层解决不了的事情,如果有,那么就加俩层。

变成这样之后,是不是感觉简洁很多了,没有错Infrustructure框架层做的事情就是这个,我们将创建具体对象的工作交给了框架,从此以后,CashBusiness的依赖关系就稳定了,我们也过上了衣食无忧,逍遥快乐的日子。

3.Unity的基本使用

上面Infrustructure的功能,我们使用的就是Unity。

public static class IocContainer
{
private static IUnityContainer _container = null;
static IocContainer()
{
_container = new UnityContainer();
}
/// <summary>
/// 注册一个实例作为T的类型
/// </summary>
/// <typeparam name="T">需要注册的类型</typeparam>
/// <param name="instance">需要注册的实例</param>
public static void Register<T>(T instance)
{
_container.RegisterInstance<T>(instance);
}
/// <summary>
/// 注册一个名为name的T类型的实例
/// </summary>
/// <typeparam name="T">需要注册的类型</typeparam>
/// <param name="name">关键字名称</param>
/// <param name="instance">实例</param>
public static void Register<T>(string name, T instance)
{
_container.RegisterInstance(name, instance);
}
/// <summary>
/// 将类型TFrom注册为类型TTo
/// </summary>
/// <typeparam name="TFrom"></typeparam>
/// <typeparam name="TTo"></typeparam>
public static void Register<TFrom, TTo>() where TTo : TFrom
{
_container.RegisterType<TFrom, TTo>();
}
/// <summary>
/// 将类型TFrom注册为类型TTo
/// </summary>
/// <typeparam name="TFrom"></typeparam>
/// <typeparam name="TTo"></typeparam>
/// <typeparam name="lifetime"></typeparam>
public static void Register<TFrom, TTo>(LifetimeManager lifetime) where TTo : TFrom
{
_container.RegisterType<TFrom, TTo>(lifetime);
}
/// <summary>
/// 将类型TFrom注册名为name类型TTo
/// </summary>
/// <typeparam name="TFrom"></typeparam>
/// <typeparam name="TTo"></typeparam>
public static void Register<TFrom, TTo>(string name) where TTo : TFrom
{
_container.RegisterType<TFrom, TTo>(name);
}
/// <summary>
/// 通过关键字name来获取一个实例对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
public static T Resolve<T>(string name)
{
return _container.Resolve<T>(name);
}
/// <summary>
/// 获取一个为T类型的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
/// <summary>
/// 获取所有注册类型为T的对象实例
/// </summary>
/// <typeparam name="T">需要获取的类型的对象</typeparam>
/// <returns></returns>
public static IEnumerable<T> ResolveAll<T>()
{
return _container.ResolveAll<T>();
}
}

上面代码中Register就是将对象或实现类,注册到Ioc容器中,在需要使用的地方再调用Resolve获取对象即可,这样,无论我们在哪里需要,都可以用Ioc容器来获取对象,而不再需要使用new来创建对象了。

4.使用配置文件配置注入

但是,我们显然不满足于这样,我们还想把实现,彻彻底底的从代码中移除,这里我们就可以借助配置文件来实现了。首先,我们在IocContainer里添加一个静态构造函数,让程序在初次使用IocContainer时加载配置,

static IocContainer()
{
_container = new UnityContainer(); object unitySection = ConfigurationManager.GetSection("unity");
if (unitySection == null) return; UnityConfigurationSection section = (UnityConfigurationSection)unitySection;
section.Configure(_container, "Default");
}
/// <summary>
/// 从文件中加载Unity注入的对象和映射关系等
/// </summary>
/// <param name="configFile">Unity容器配置文件的路径</param>
public static void LoadUnityConfig(string configFile)
{
string filePath = configFile;
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = filePath }; Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection unitySection = (UnityConfigurationSection)configuration.GetSection("unity");
foreach (var item in unitySection.Containers)
{
_container.LoadConfiguration(unitySection, item.Name);
}
}

web.config(WEB项目是在web.config)里配置我们配置文件的路径,在configuration节点中添加如下配置

<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity configSource="unity.config"/>

接下来我们来配置我们的unity.config文件(这里unity.config是放在运行目录下的,WEB网站下应该是与bin目录同级)

<?xml version="1.0" encoding="utf-8" ?>
<unity xmlns= "http://schemas.microsoft.com/practices/2010/unity ">
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
<!--注入对象-->
<typeAliases>
<!--表示单例-->
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" />
<!--表示每次使用都进行创建-->
<typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager,Microsoft.Practices.Unity" />
</typeAliases>
<container name= "Default">
<!--配置sql-->
<!--<register type= "接口类,接口dll" mapTo= "实现类,实现dll"  name="实例名">-->
<register type= "MJD.Framework.Sql.Interfaces.IConnectionFactory,MJD.Framework.Sql" mapTo= "MJD.Framework.Sql.Oracle.ConnectionFactory,MJD.Framework.Sql.Oracle">
<lifetime type="singleton" />
</register>
</container>
</unity>

这样,我们就可以将实现彻底的解耦出来了。怎么样,是不是很酷?以后再也不需要再去更改代码了,直接配置就可以了。

5.三种生命周期

在上面的配置中,眼尖的你可能会发现,在register下还配置了一个lifetime,type填写的是一个别名。这里就是所谓的生命周期,在Unity中有三种生命周期

ContainerControlledLifetimeManager,即单例,生命周期与容器的生命周期一样,一般如果我们使用静态的容器,那么这个就等同于我们的单例模式;
TransientLifetimeManager,临时的,即每次创建容器都会new一个对象给我们使用;

HierarchicalLifetimeManager,这个用得比较少,假如容器有分层,有子容器,那么父容器与子容器中的对象都是单例的,但是子类与父类里的对象不是同一个;

控制反转-Ioc之Unity的更多相关文章

  1. 控制反转IOC的依赖注入方式

    引言: 项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常.因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来 ...

  2. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...

  3. 20181123_控制反转(IOC)和依赖注入(DI)

    一.   控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...

  4. C#依赖注入控制反转IOC实现详解

    原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. ...

  5. 控制反转IoC简介

    控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...

  6. 浅析“依赖注入(DI)/控制反转(IOC)”的实现思路

    开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...

  7. 控制反转IOC与依赖注入DI

    理解 IOC  http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例      的http:// ...

  8. 控制反转IOC与依赖注入DI【转】

    转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...

  9. 依赖注入(DI)和控制反转(IOC)

    依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...

随机推荐

  1. C:\WINDOWS\system32\wmp.dll”受到“Windows 系统文件保护”

    在VC# 2005 中,要是打包的程序中包含了Windows Media Player 这个组件的话,在生成解决方案的过程中会提示出错:  "错误1,应将“wmp.dll”排除,原因是其源文 ...

  2. python基础阶段 经典练习题 拾英札记(2)

    因为编程的练习题是交互式的,在不断调试和不断渐进完善中,你会有一种成就感和快乐感,不断的修缮,不断的尝试. 其实,认知自己,和探索世界,也是这样的啊. 只要不放弃,要坚持. #7  根据列表lt,实现 ...

  3. [转载] 详述三种现代JVM语言--Groovy,Scala和Clojure

    转载自http://www.tuicool.com/articles/jYzuAv和http://www.importnew.com/1537.html 在我与Martin Fowler曾经合作呈现的 ...

  4. SICK激光雷达LMS511测量数据说明

    帧结构说明 LMS511的官方手册存在几个版本,在<Laser Measurement Systems of the LMS500 Product Family>的英文手册中,对单次(连续 ...

  5. MVC中提交包含HTML代码的页面处理方法(尤其是在使用kindeditor富文本编辑器的时候)

    针对文本框中有HTML代码提交时,mvc的action默认会阻止提交,主要是出于安全考虑.如果有时候需求是要将HTML代码同表单一起提交,那么这时候我们可以采取以下两种办法实现: 1.给Control ...

  6. vue+node+webpack搭建环境

    一.环境搭建 1.1.去官网安装node.js( http://www.runoob.com/nodejs/nodejs-install-setup.html  ) 注意node的版本,只有支持和谐模 ...

  7. osap一站式分析模型

    运营系统分析平台技术设计: 项目定义于运营系统关键指标的数据分析 关键代码描述: HiveWriter 主要用于写hive表抽象,包括加分区,写hive表,写success文件: import org ...

  8. React服务器端渲染值Next.js

    昨天leader给分配了新任务,让熟悉一下ssr,刚开始有点懵,啥玩意?百度了一下,不就是服务器端渲染(server side render,简称: ssr). ssr简介 服务端渲染一个很常见的场景 ...

  9. 2943:小白鼠排队-poj

    2943:小白鼠排队 总时间限制:  1000ms 内存限制:  65536kB 描述 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子.现在称出每只白鼠的重量,要求按 ...

  10. 基于 HTML5 Canvas 的简易 2D 3D 编辑器

    不管在任何领域,只要能让非程序员能通过拖拽来实现 2D 和 3D 的设计图就是很牛的,今天我们不需要 3dMaxs 等设计软件,直接用 HT 就能自己写出一个 2D 3D 编辑器,实现这个功能我觉得成 ...