码迷,mamicode.com
首页 > 其他好文 > 详细

IOC

时间:2016-07-02 08:03:16      阅读:250      评论:0      收藏:0      [点我收藏+]

标签:

如果你想学懂IOC,你就必须先学懂设计模式的6大原则之中的2种

即:

1、SRP:单一职责

2、DIP:依赖倒置

因为IOC的基础就是这2个模式。

单一职责:

你的代码遵循了单一职责,既每个对象只负责一个职责,对象与对象(程序集、层)之间协同工作(依赖)来完成整个项目。

把整个项目通过分解的形式,形成一个一个小的工能块,像装组装电脑一样,各自负责自己的事情。

依赖倒置:

在 单一职责 的基础之上,我们应该如何处理相互依赖呢?解决办法就是用接口和抽像,而不是具体的对象与对象之间,上下层之间,直接依赖(关联)。

因为接口可以视为一个标准,只要符合的对象都可以使用,而不是具体的写死某个对象。试想一下你的电脑如果内存、硬盘、CPU都焊死在主板上,后果是什么呢?就是不可维护。那么主板只需要定义好,内存\CPU\DISK的插槽就可以了。这些硬件在符合接口约束的情况下就可以自由升级。程序设计也是这个道理。

 

我们以一个消息服务为例:

MessageService 依赖的是接口 IMessage
            MessageService MessageService1 = new MessageService();
            MessageService1.Send("你好呀!");

    class MessageService
    {
        private IMessage Message;
        public MessageService()
        {
            Message = new WeiXin();
        }

        public void Send(string value)
        {
            Message.Send(value);
        }
    }


    interface IMessage
    {
        void Send(string value);
    }


    class WeiXin : IMessage
    {
        public void Send(string value)
        {
            Console.WriteLine("WeiXin:{0}", value);
        }
    }

 

在构造函数中 Message = new WeiXin(); 直接依赖,如果项目更改成用 电话通知呢?我们必须要修改消息服务类。

我们把它升级为:

            MessageService MessageService1 = new MessageService(new WeiXin());
            MessageService1.Send("你好呀!");
    class MessageService
    {
        private IMessage Message;
        public MessageService(IMessage message)
        {
            Message = message;
        }

        public void Send(string value)
        {
            Message.Send(value);
        }
    }

 

这种由调用端传入依赖实体的方式,就叫做依赖注入(是由它的上层来指定所依赖的具体对象)

 

如果需求更改,变成 电话通知呢?改调用端代码

MessageService MessageService2 = new MessageService(new TelPhone());
            MessageService2.Send("你好呀!");

这样调用端是不稳定的,有没有一种方法解决这个难受的问题呢?有,就是工厂系列模式

            string heroTypeReflector = System.Configuration.ConfigurationManager.AppSettings["heroTypeReflector"];

            string assemblyName = heroTypeReflector.Split(,)[0];
            string typeName = heroTypeReflector.Split(,)[1];
            IMessage  message =(IMessage)Activator.CreateInstance(assemblyName, typeName).Unwrap();

            MessageService MessageService3 = new MessageService(message);
            MessageService3.Send("你好呀!");

这样再也不怕升级了。当升级的时候,只需要增加相对应的配置文件,和符合调用接口的 IMessage  实体。

调用端(上端)也变的稳定了。

这一系列的思路就叫做IOC

IOC:控制反转(就是把依赖的选择权交由第三方(通常是配置文件)来做)

它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模块的类中直接通过new来获取。

IOC有2种常见的实现方式:

1、DI:依赖注入DI是Dependency Injection缩写,它提出了“哪些东东的控制权被反转了,被转移了?”,它也给出了答案:“依赖对象的创建获得被反转”。

把模块看成是一个独立的功能,它的依赖是由自己控制,也可以由外部控制。如果它由外部来控制,这个过程就叫做依赖注入。
这种方式是一种可插拔的模块化思路。也叫做依赖倒置原则。也叫解除耦合原则。

2、服务定位

 

,控制反转只是一种开发思想,意思是类的创建 new 的过程叫控制、反转就是将这个权力交出去,没有具体的解决方案。

那么控制反转的具体实现方案有哪些呢?

目前,比较流行的Ioc容器有以下几种:

1. Ninject: http://www.ninject.org/

2. Castle Windsor: http://www.castleproject.org/container/index.html

3. Autofac: http://code.google.com/p/autofac/

4. StructureMap: http://docs.structuremap.net/

5. Unity: http://unity.codeplex.com/

注:根据园友 徐少侠 的提醒,MEF不应该是IoC容器。我又查阅了一些资料,觉得MEF作为IoC容器是有点勉强,它的主要作用还是用于应用程序扩展,避免生成脆弱的硬依赖项。

6. MEF: http://msdn.microsoft.com/zh-cn/library/dd460648.aspx

另外,园友 aixuexi 提出Spring.NET也是比较流行的IoC容器。

7. Spring.NET: http://www.springframework.net/

园友 wdwwtzy 也推荐了一个不错的IoC容器:

8. LightInject: http://www.lightinject.net/ (推荐使用Chrome浏览器访问)

 

这里我们要讲的是微软的Unity

Unity 是一种容器,为什么叫它容器呢?大概意思是它集中管理了一系列的注入过程。

 

Unity 容器的6个主要功能

1. 它提供了创建(或者装配)对象实例的机制(接口),而这些对象实例可能还包含了其它被依赖的对象实例。(属性、构造、函数)

2. Unity允许将预先配置的对象注入到类中(一般为配置文件),实现了inversion of control (IoC)的功能。在Unity中,支持constructor injection(构造器注入), property setter injection(属性设值注入)以及method call injection(方法注入)。ps:这里的方法注入与Martin Fowler定义的接口注入类似而稍有区别。

3. 支持容器的体系结构。一个容器可以有子容器,允许从子容器到父容器的对象定位查询。(?这个我不懂)


4. 可以通过配置文件进行准备和配置容器。

5. 不会影响到类的定义(属性设值注入和方法注入除外),这也是轻量级容器的一个体现。(?这个我不懂)

6. 支持自定义的容器扩展。(?这个我不懂)

 

Unity 有5种使用场景

1、接口注入

            container.RegisterType<IMessage, WeiXin>();
            container.RegisterType<IMessageService, MessageService>();

            IMessageService IMessageService1 = container.Resolve<IMessageService>();
            IMessageService1.Send("你好呀!");

将 IMessageService 注册到 MessageService

将 IMessage 注册到 WeiXin

类型映射是我们无法回避的一个问题,同时也是一系列工厂模式的根本出发点

如果需要使用同样的接口(或基类)注册多个映射,可以指定名称来区分每个映射。

如果是泛型在接口后面加一个 `1

2、属性注入[Dependency]

        [Dependency]
        public ILogger log
        {
            get { return logger; }

            set { logger = value; }
        }

 

3、构造注入[InjectionConstructor]

        [InjectionConstructor]
        public MessageService(IMessage message)
        {
            Message = message;
        }

 

对于构造器注入,Unity支持两种方式的依赖注入:

1、自动依赖注入

2、通过打标签标识。[InjectionConstructor]

具体来说,对于只有单一构造函数的目标类,可以使用自动依赖注入的方式,而对于有多个构造函数的目标类,则应该使用在构造函数上打标签的方式来进行注入。

这是因为对于具有多个构造器的目标类,如果没有发现标有InjectionConstructor标签的构造器,Unity会自动使用参数最多的构造器。如果参数最多的构造有多个,就会报错。

 

4、函数注入[InjectionMethod]

        [InjectionMethod]
        public void Inject(ILogger ilogger1)
        {
            ILogger1 = ilogger1;
        }

 

5、单例模式

container.RegisterType<IMessageService, MessageService>(new ContainerControlledLifetimeManager());

把一个已经存在的对象注册成单例模式

container.RegisterType<CommonOrder>(new ContainerControlledLifetimeManager());

把一个已经存在的对象注册成单例模式

            container.RegisterType<CommonOrder>("s1", new ContainerControlledLifetimeManager());
            container.RegisterType<CommonOrder>("s2", new ContainerControlledLifetimeManager());

调用

CommonOrder CommonOrder1 = container.Resolve<CommonOrder>("s1");
CommonOrder CommonOrder2 = container.Resolve<CommonOrder>("s2");

 

为了实现单例模式,我们通常的做法是,在类中定义一个私有构造函数,和一个静态公开只读自身字段。但是我觉得这种做法将对象的生命周期管理与类本身耦合在了一起,与SRP:单一职责原则相违背。所以我觉得遇到需要使用单例的地方,应该将生命周期管理的职责转移到对象容器上,而我们的类依然是一个干净的类。

将Unity应用于单例模式,主要有两种使用场景:

(1)将类型注册为单例;

(2)将已有对象注册为单例。


默认情况下,直接使用RegisterType(不指定LifetimeManager),然后Resolve所得到的对象的生命周期是短暂的,容器并不保存对象的引用,每次调用Resolve方法我们都会得到一个新对象。然而,当我们指定了ContainerControlledLifetimeManager参数后,容器在第一次调用Resolve方法时会创建一个新对象,此后在每次调用Resolve时,都会返回之前创建的对象。


除此之外,Unity还扩展了单例的使用方式。例如,我需要把某个类设计为单例,但是发现在应用中我们需要这个类的两个单例,分别有不同的用途,这时,使用Unity的类型与名称组合的标识键,就可以满足这种使用场景。

 

 

 

 

http://www.cnblogs.com/fuchongjundream/p/3915391.html

 

IOC

标签:

原文地址:http://www.cnblogs.com/lystory/p/5622408.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!