设计模式之IOC模式

Posted 冬冬他哥哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之IOC模式相关的知识,希望对你有一定的参考价值。

 一、什么是Ioc

  IoC(Inverse of Control)的字面意思是控制反转,它包括两个内容: 控制、反转

  可以假设这样一个场景:火车运货,不同类型的车厢运送不同类型的货物,板车运送圆木,罐车运送柴油,箱车运送水果。那么对于运送货物这件事,需是列车挂不同的车厢运送货物。显然列车和运送货物之间是有依赖关系的(控制:依赖关系)。我们把列车挂什么样的车厢交给调度中心,而不是交给列车决定,这就形成了依赖反转。

  因为IoC确实不够开门见山,因此业界曾进行了广泛的讨论,最终软件界的泰斗级人物Martin Fowler提出了DI(依赖注入:Dependency Injection)的概念用以代替IoC,即让调用类对某一接口实现类的依赖关系由第三方(容器或协作类)注入,以移除调用类对某一接口实现类的依赖。“依赖注入”这个名词显然比“控制反转”直接明了、易于理解。 

依赖注入和控制反转是同一概念吗?

        根据上面的讲述,应该能看出来,依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

        其实IoC/DI对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC/DI容器来创建并注入它所需要的资源了。

这么小小的一个改变其实是编程思想的一个大进步,这样就有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

二、几个相似相关的概念

依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。

控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。

依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。

IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。

三、Ioc的类型

1、构造函数注入 

public Class SayHello
{
    private People _people;
    public SayHello(People  p)

    {
        _people=p;
    }

public void Say()
    {
        _people.Say();

    }

}

2、属性注入

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using VisionLogic.Training.DependencyInjection.Scenario; 
namespace VisionLogic.Training.DependencyInjection.Scenario.UnitTest 
{ 
    [TestClass] 
    public class SetterInjectionTest 
    { 
        class Client 
        { 
            private IWeatherReader reader; 
            public IWeatherReader Reader 
            { 
                get { return reader; } 
                set { reader = value; } 
            } 
        }

        [TestMethod] 
        public void Test() 
        { 
            IWeatherReader reader = new Assembler<IWeatherReader>().Create(); 
            Client client = new Client(); 
            client.Reader = reader; 
            Assert.IsNotNull(client.Reader); 
        } 
    } 
}

也可以写一个Setter方法

3、接口注入

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using VisionLogic.Training.DependencyInjection.Scenario; 
namespace VisionLogic.Training.DependencyInjection.Scenario.UnitTest 
{ 
    [TestClass] 
    public class InterfaceInjectionTest 
    { 
        interface IClientWithWeatherReader 
        { 
            IWeatherReader Reader { get; set;} 
        } 

        class Client : IClientWithWeatherReader 
        { 
            private IWeatherReader reader; 

            #region IClientWithWeatherReader Members 
            public IWeatherReader Reader 
            { 
                get { return reader; } 
                set { reader = value; } 
            } 
            #endregion 
        } 

        [TestMethod] 
        public void Test() 
        { 
            IWeatherReader reader = new Assembler<IWeatherReader>().Create(); 
            Client client = new Client(); 
            IClientWithWeatherReader clientWithReader = client; 
            clientWithReader.Reader = reader; 
            Assert.IsNotNull(clientWithReader.Reader); 
        } 
    } 
} 

四、一个例子

C#

using System; 
namespace VisionLogic.Training.DependencyInjection.Scenario.Attributer 
{ 
    /// <summary> 
    /// 抽象的处理对象 
    /// </summary> 
    public interface IObjectWithGuid 
    { 
        string Guid { get; set;} 
    } 
}

定义需要注入的限制接口,并用一个Attribute管理它 
C#

using System; 
namespace VisionLogic.Training.DependencyInjection.Scenario.Attributer 
{ 
    /// <summary> 
    /// 需要注入的用以限制最大数量的接口 
    /// </summary> 
    public interface ICapacityConstraint 
    { 
        int Max { get;} 
    } 

    public class CapacityConstraint : ICapacityConstraint 
    { 
        private int max; 
        public CapacityConstraint(){this.max = 0;} // 默认情况下不限制 
        public CapacityConstraint(int max) { this.max = max; } 
        public int Max { get { return max; } } 
    } 

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
    public class ConstraintAttribute : Attribute 
    { 
        private ICapacityConstraint capacity; 
        public ConstraintAttribute(int max) { this.capacity = new CapacityConstraint(max); } 
        public ConstraintAttribute() { this.capacity = null; } 
        public ICapacityConstraint Capacity { get { return capacity; } } 
    } 
} 

Assembler上增加通过Attribute注入限制的响应。 

using System; 
using System.Collections.Generic; 
namespace VisionLogic.Training.DependencyInjection.Scenario.Attributer 
{ 
    public class Assembler 
    { 
        /// <summary> 
        /// 登记相关类型对“最大容量”属性的使用情况 
        /// </summary> 
        private IDictionary<Type, ConstraintAttribute> attributeRegistry = new Dictionary<Type, ConstraintAttribute>(); 

        /// <summary> 
        /// 登记每个类型(如须受到“最大容量”属性限制的话),实际已经创建的对象数量 
        /// </summary> 
        private IDictionary<Type, int> usageRegistry = new Dictionary<Type, int>(); 
        public T Create<T>() where T : IObjectWithGuid, new() 
        { 
            ICapacityConstraint constraint = GetAttributeDefinedMax(typeof(T)); 
            if ((constraint == null) || (constraint.Max <= 0)) // max <= 0 代表是不需要限制数量的。 
                return InternalCreate<T>(); 
            else 
            { 
                if (usageRegistry[typeof(T)] < constraint.Max) // 检查是否超出容量限制 
                { 
                    usageRegistry[typeof(T)]++; // 更新使用情况注册信息 
                    return InternalCreate<T>(); 
                } 
                else 
                    return default(T); 
            } 
        } 

        // helper method 
        // 直接生成特定实例,并setter 方式注入其guid。 
        private T InternalCreate<T>() 
        where T : IObjectWithGuid, new() 
        { 
            T result = new T(); 
            result.Guid = Guid.NewGuid().ToString(); 
            return result; 
        } 

        /// helper method. 
        // 获取特定类型所定义的最大数量, 同时视情况维护attributeRegistry 和usageRegistry 的注册信息。 
        private ICapacityConstraint GetAttributeDefinedMax(Type type) 
        { 
            ConstraintAttribute attribute = null; 
            if (!attributeRegistry.TryGetValue(type, out attribute)) //新的待创建的类型 
            { 
                // 填充相关类型的“最大容量”属性注册信息 
                object[] attributes = type.GetCustomAttributes(typeof(ConstraintAttribute), false); 
                if ((attributes == null) || (attributes.Length <= 0)) 
                    attributeRegistry.Add(type, null); 
                else 
                { 
                    attribute = (ConstraintAttribute)attributes[0]; 
                    attributeRegistry.Add(type, attribute); 
                    usageRegistry.Add(type, 0); // 同时补充该类型的使用情况注册信息 
                } 
            } 
            if (attribute == null) 
                return null; 
            else 
                return attribute.Capacity; 
        } 
    } 
} 
技术分享

4.2对方案的测试 

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using VisionLogic.Training.DependencyInjection.Scenario.Attributer; 
namespace VisionLogic.Training.DependencyInjection.Scenario.UnitTest.Attributer 
{ 
    [TestClass()] 
    public class AssemblerTest 
    { 
        public abstract class ObjectWithGuidBase : IObjectWithGuid 
        { 
            protected string guid; 
            public virtual string Guid 
            { 
                get { return guid; } 
                set { guid = value; } 
            } 
        } 

        [Constraint(2)] // 通过属性注入限制 
        public class ObjectWithGuidImplA : ObjectWithGuidBase { } 
        [Constraint(0)] // 通过属性注入限制 
        public class ObjectWithGuidImplB : ObjectWithGuidBase { } 
        [Constraint(-5)] // 通过属性注入限制 
        public class ObjectWithGuidImplC : ObjectWithGuidBase { } 
        public class ObjectWithGuidImplD : ObjectWithGuidBase { } 

        [TestMethod] 
        public void Test() 
        { 
            Assembler assembler = new Assembler(); 
            for (int i = 0; i < 2; i++) 
            Assert.IsNotNull(assembler.Create<ObjectWithGuidImplA>()); 
            Assert.IsNull(assembler.Create<ObjectWithGuidImplA>()); // 最多两个 
            for (int i = 0; i < 100; i++) 
            Assert.IsNotNull(assembler.Create<ObjectWithGuidImplB>()); // 不限制 
            for (int i = 0; i < 100; i++) 
            Assert.IsNotNull(assembler.Create<ObjectWithGuidImplC>()); // 不限制 
            for (int i = 0; i < 100; i++) 
            Assert.IsNotNull(assembler.Create<ObjectWithGuidImplD>()); // 不限制 
        } 
    } 
} 

 




以上是关于设计模式之IOC模式的主要内容,如果未能解决你的问题,请参考以下文章

工厂模式 ioc dom4j 反射之我的一点理解

Spring之Ioc原理

Java开发Spring之IOC详解第一篇(xml开发常用APIben标签DI依赖注入)

Spring之IOC

Spring之IOC

PHP设计模式之策略模式