一. 温故而知新
在开始学习Unity框架之前,有必要温习一下 【依赖倒置原则】和【手写IOC】, 因为我们框架代码的构建都是基于【依赖倒置原则】的,而Unity框架的核心思想就是IOC和DI,所以有必要了解通过【反射+工厂+配置文件】来实现手写IOC的原理。
废不多说,简单提炼一下依赖原则的核心理念:面向接口编程。上层(UI层)不直接依赖于下层,而是依赖于下层对应的接口,下层去实现该接口。
经典案例:业务层连接数据库,依赖接口,可以实现不改代码轻松切换数据库的目的。
手动创建对象的三个阶段:直接new实例化→面向接口编程→将创建对象的交给工厂【手写IOC】。
1 #region 手动创建对象几个阶段 2 { 3 Console.WriteLine("--------------一.复习依赖倒置原则和手写IOC(简单工厂+反射+配置文件)----------------"); 4 //1. 直接创建(需要添加对Service层的引用) 5 Console.WriteLine("--------------1. 直接创建----------------"); 6 AndroidPhone androidPhone1 = new AndroidPhone(); 7 androidPhone1.Call(); 8 9 //2. 利用接口进行改造(需要添加对Service和Interface层的引用) 10 Console.WriteLine("--------------2. 利用接口进行改造----------------"); 11 IPhone androidPhone2 = new AndroidPhone(); 12 androidPhone2.Call(); 13 14 //3. 手写IOC(只需要添加Interface层的引用,但需要把Service层生成的DLL拷贝到该项目bin下) 15 Console.WriteLine("--------------3. 利用接口进行改造----------------"); 16 IPhone androidPhone3 = ObjectFactory.CreateObject<IPhone>(); 17 androidPhone3.Call(); 18 19 //总结:第三个阶段基本上已经是我们自己写容器的最高层次 20 //下面我们将借助微软的第三方容器Unity来创建 21 22 } 23 #endregion
依赖倒置原则详见:http://www.cnblogs.com/yaopengfei/p/7101347.html
手写IOC详见:http://www.cnblogs.com/yaopengfei/p/6891286.html
二. Unity深入浅出
(一). Unity介绍
1. Unity的获取方式
①:下载网址:http://unity.codeplex.com/
②:通过Nuget获取 (目前最新版本为4.0.1)
2. Unity是什么?
Unity是一个IOC容器,用它可以来创建对象,代替手写反射,它可以实现依赖注入(DI),它出自于微软。.Net平台下类似的其它IOC框架还有:Spring.Net、AutoFac、Castle等等。
3. IOC的含义
IOC是一种目标,IOC的含义为控制反转,即原本上端(UI层)直接创建或使用的对象,交给第三方容器来装配和创建。
4. DI的含义
DI是一种手段,DI的含义为依赖注入,Unity提供三种方式分别是:属性注入、方法注入、构造函数注入。
(二). 使用Unity来创建对象
1. 创建对象的步骤
①:声明IUnityContainer容器。
②:通过RegisterType注册新类型 或者 通过RegisterInstance注册已经存在的类型。
③:通过Resove解析对象。
特别注意:注册类型时,可以指定名称来注册,用于同时创建注册多个类型时,Resove可以通过指定的注册名称来针对指定解析。
2. 代码说明
①:代码结构(后面所有的代码说明都是基于这个结构的)
详细说明:各个类的内容待写。
②:直接创建简单对象(需要添加对Interface层和Service层的引用)
1 { 2 Console.WriteLine("------------------- 二. Unity入门 -------------------"); 3 Console.WriteLine("------------------- 01-直接创建对象 -------------------"); 4 IUnityContainer container = new UnityContainer(); 5 //进行注册,可以是: 接口-类、父类-子类、抽象类-子类。 6 //container.RegisterType<IPhone, AndroidPhone>(); 7 //也可以用实例注册已经存在的对象 8 AndroidPhone android = new AndroidPhone(); 9 container.RegisterInstance<IPhone>(android); 10 //解析对象 11 IPhone phone = container.Resolve<IPhone>(); 12 phone.Call(); 13 //我们会发现,虽然注册了AndroidPhone对象,但是该对象中的三个属性并没有实例化,依旧为空 14 Console.WriteLine("phone.iHeadphone==null? {0}", phone.iHeadphone == null); 15 Console.WriteLine("phone.iMicrophone==null? {0}", phone.iMicrophone == null); 16 Console.WriteLine("phone.iPower==null? {0}", phone.iPower == null); 17 }
详解:上述代码我们分别通过RegisterType注册类型、RegisterInstance注册已经存在的类型,我们会发现最终生成AndoridPhone中的三个属性并没有被实例化,那么怎么实例化里面的属性呢?这就涉及到后面的依赖注入了。
③. 指定命名来创建对象(需要添加对Interface层和Service层的引用)
1 { 2 Console.WriteLine("------------------- 03-同时创建多个对象 -------------------"); 3 //可以通过添加一个参数来区分 4 IUnityContainer container = new UnityContainer(); 5 //注册类型时(指定命名) 6 container.RegisterType<IPhone, AndroidPhone>(); 7 container.RegisterType<IPhone, ApplePhone>("apple"); 8 container.RegisterType<IPhone, AndroidPhone>("android"); 9 //依赖注入 10 container.RegisterType<IMicrophone, Microphone>(); 11 container.RegisterType<IHeadphone, Headphone>(); 12 container.RegisterType<IPower, Power>(); 13 //解析对象 14 IPhone iphone1 = container.Resolve<IPhone>(); 15 iphone1.Call(); 16 //解析对象(指定命名) 17 IPhone iphone2 = container.Resolve<IPhone>("apple"); 18 iphone2.Call(); 19 IPhone iphone3 = container.Resolve<IPhone>("android"); 20 iphone3.Call(); 21 22 //获取所有已注册且指定命名的对象(未指定命名的不能获取) 23 var list = container.ResolveAll<IPhone>(); 24 25 }
详解:注册类型时,如果默认不指定命名,则后面的会覆盖前面的,解析多个对象时,永远是最后一个注册的类型的对象。 所以RegisterType指定命名 、Resolve解析对象指定命名广泛用于同时创建多个对象的情况。
我们发现上述代码有三句是依赖注入的,这个在下面讲解。
(三). 依赖注入的三种形式
Unity实现依赖注入有三种形式,分别是构造函数注入、属性注入、方法注入,分别对应三个特性:【InjectionConstructor】、【Dependency】、【InjectionMethod】,加上这三个特性表明构造函数中、属性中、方法中需要注入对象,使其实例化。
方式一:属性注入。
有WinPhone1类,实现了Iphone接口。其中WinPhone1类中的iMicrophone和iHeadphone两个属性上分别添加【Dependency】和【Dependency("fk")】,表明该属性对应的对象需要注入,其中iHeadphone需要Unity容器"指定命名"来注册类型。
1 public interface IPhone 2 { 3 void Call(); 4 IMicrophone iMicrophone { get; set; } 5 6 IHeadphone iHeadphone { get; set; } 7 8 IPower iPower { get; set; } 9 }