IOC Unity

IOC Unity

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

依赖倒置原则:
A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

Unity是微软patterns & practices组用C#实现的轻量级,可扩展的依赖注入容器,它为方便开发者建立松散耦合的应用程序。

引言

在我们的工作中经常会用到三层架构。UI层复杂界面;BLL层复杂业务逻辑;DLL复杂数据库操作。调用方式为 UI层调用BLL层,BLL层调用DLL层,然后为了抽象,我们会添加一个IBLL层与IDLL层,分别为BLL和DLL的抽象。

如下代码:

IBLL层代码

namespace IBLL
{
    public interface IPhone
    {
        void Call();
    }
}

BLL层代码

namespace BLL
{
    public class ApplePhone : IPhone
    {
        public void Call()
        {
            Console.WriteLine("ApplePhone Call!");
        }
    }
}

BLL层代码

namespace BLL
{
    public class AndroidPhone : IPhone
    {
        public void Call()
        {
            Console.WriteLine("AndroidPhone Call!");
        }
    }
}

界面层:

IPhone phone = new ApplePhone();
phone.Call();

但是这样调用,会让界面依赖于实现层。这种调用方式违背了依赖倒置原则。

当然我们也可以使用工厂模式+配置文件的方式进行优化。

不过我们这里介绍一个更好用的东西 Unity 容器。

Unity容器的初步应用

添加Unity包

右击引用-->管理NuGet程序包-->搜索Unity-->安装。(使用的为vs2017,不过过程基本类似)

使用

基本方式

IUnityContainer unityContainer = new UnityContainer();//声明一个容器
unityContainer.RegisterType<IPhone, ApplePhone>();//将IPhone与ApplePhone进行映射
IPhone phone = unityContainer.Resolve<IPhone>();//反射创建对象
phone.Call();//调用方法
//输出:ApplePhone Call!

别名方式

IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType<IPhone, ApplePhone>("Apple");//设置别名
unityContainer.RegisterType<IPhone, AndroidPhone>("Android");
IPhone phone1 = unityContainer.Resolve<IPhone>("Apple");//通过别名 创建对象
phone1.Call();//输出:ApplePhone Call!
IPhone phone2 = unityContainer.Resolve<IPhone>("Android");
phone2.Call();//输出:AndroidPhone Call!

依赖注入,多层架构

现在我们再添加一些代码:

IBLL层

namespace IBLL
{
    public interface IPower
    {
    }
}

BLL层

namespace BLL
{
    public class Power : IPower
    {
    }
}
namespace BLL
{
    public class WinPhone : IPhone
    {
        public WinPhone()
        {
            Console.WriteLine("WinPhone 无参数构造函数");
        }

        public WinPhone(IPower power)
        {
            Console.WriteLine("WinPhone IPower参数构造函数");
        }
        public void Call()
        {
            Console.WriteLine("WinPhone Call!");
        }

    }
}

我们对代码做了如下的修改:

  1. 给IBLL层添加了一个IPower接口
  2. 在BLL层的类Power中实现了它
  3. 添加了一个实现IPhone接口的WinPhone类,并给这个类创建了一个无参数的构造函数和一个有一个参数的构造函数。

然后我们在界面层调用

IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType<IPhone, WinPhone>();
var phone = unityContainer.Resolve<IPhone>();
phone.Call();

在调用时系统抛出一个异常:

Resolution of the dependency failed, type = 'IBLL.IPhone', name = '(none)'.
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, IBLL.IPower, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was: 
  Resolving BLL.WinPhone,(none) (mapped from IBLL.IPhone, (none))
  Resolving parameter 'power' of constructor BLL.WinPhone(IBLL.IPower power)
    Resolving IBLL.IPower,(none)

大致意思为缺少IBLL.IPower的映射。

我们再次修改界面层的调用:

IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType<IPhone, WinPhone>();
unityContainer.RegisterType<IPower, Power>();//添加接口IPower的映射
var phone = unityContainer.Resolve<IPhone>();
phone.Call();

/*
 输出:
 WinPhone IPower参数构造函数
 WinPhone Call!
 */

我们不难发现创建的WinPhone对象时所使用的构造函数为 带有参数的构造函数,并且通过之前配置的映射将参数也实例化了。

生命周期管理

IUnityContainer container = new UnityContainer();
container.RegisterType<IPhone, AndroidPhone>();//默认 瞬时 每一次创建的实例对象都是新的
container.RegisterType<IPhone, AndroidPhone>(new TransientLifetimeManager());//默认  瞬时  每一次创建的实例对象都是新的
container.RegisterType<IPhone, AndroidPhone>(new ContainerControlledLifetimeManager());//容器单例 每一次的对象都是一样的相当于单例模式。单例就不要自己实现
container.RegisterType<IPhone, AndroidPhone>(new PerThreadLifetimeManager());//线程单例:相同线程的实例相同 不同线程的实例不同   web请求/多线程操作

配置文件

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路径
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

IUnityContainer container = new UnityContainer();
section.Configure(container, "testContainer");
IPhone phone = container.Resolve<IPhone>("Apple");
phone.Call();

IPhone android = container.Resolve<IPhone>("Android");
android.Call();

IPhone winPhone = container.Resolve<IPhone>("Win");
winPhone.Call();

/*
 输出:
ApplePhone Call!
AndroidPhone Call!
WinPhone IPower参数构造函数
WinPhone Call!
*/

xml 如下。格式不用修改,只需要修改相应的容器和添加register标签

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
  </configSections>
  <unity>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
    <containers>
      <container name="testContainer"><!--这个是容器-->
        <register type="IBLL.IPhone,IBLL" mapTo="BLL.AndroidPhone, BLL" name="Android"/> <!--name表示别名-->
        <register type="IBLL.IPhone,IBLL" mapTo="BLL.ApplePhone, BLL" name="Apple"/>
        <register type="IBLL.IPhone,IBLL" mapTo="BLL.WinPhone, BLL" name="Win"/>
        <register type="IBLL.IPower,IBLL" mapTo="BLL.Power, BLL" />
      </container>
    </containers>
  </unity>
</configuration>

添加完毕这些之后,我们可以将BLL的引用从项目中删除(但是需要将BLL.dll拷贝到bin目录下)也是可以使用的,这样我们就完全不对底层模块的依赖,只依赖于抽象。

转载于:https://www.cnblogs.com/haowuji/p/9777178.html

前言 unity的框架,除了各大公司自己内部使用的,开源并好用的实际并不是很多,我会慢慢挖掘,依次写出自己的一点见解,错误的地方,望各路大神指正。 一、基本概念 控制反转(Inversion of Control,英文缩写为IOC),我的理解就是,原本A类要获取B类的对象,需要你在A类中自己New一个对象,那么是由A来获取并控制B的对象,IOC就是把对象获取的这个过程交给容器和依赖注入来处理,A类并不知道B的对象是哪里来的,对B对象的控制,由自己变成了其他类,官方一点的概念可以百度,这个还是蛮多的。 二、StrangeIOC基础类型 实际要理解一个框架的类型,还是要自己看源码,这里我只说一下几个重要类型的作用,这个看源码的时候有个印象,也方便理解,而且说这部分的帖子也很多,我就不再赘述了。 1.Context 上下文组件定义程序边界,也就是可以把一个程序定义成多上下文,让代码更加模块化 它提供了程序入口,也算是框架中耦合度最高的地方 2.Binder和Binding 这两个类是这个框架最重要的组成部分 Binding存储了对象的绑定关系,而Binder存储了Binding的对象 3.View和Mediator MVCS中的View层,View只用于显示,也就是View只负责管理UI,Mediator负责界面逻辑,事件响应等 4.Model MVCS中的Model层,负责数据部分 5.Command MVCS中的Control层,负责执行逻辑代码 6.Service MVCS中的Service层,负责与第三方交互,这个Service我理解的,并不是一定指代服务器,也可以是其他的软件,什么都可以,它就是我们程序对外的接口 7.Dispatcher 派发器是框架内通信主线的其中一种,用来派发消息,触发命令,从而进一步解耦 8.Signal 信号是框架内另外一种通信主线,它采用强类型,来绑定信号和命令之间的关系,实现消息响应的触发 9.ReflectionBinder 反射部分,通过binding来获取类的信息,存储在ReflectedClass中 10.injector 注入器,通过反射获取的信息,来实例化请求的对象 --------------------- 作者:蓝天小僧 来源:CSDN 原文:https://blog.csdn.net/zcaixzy5211314/article/details/80876228 版权声明:本文为博主原创文章,转载请附上博文链接!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值