理解依赖注入(IOC)

IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection)。
作用:将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调用完全面向接口。当系统重构的时候,代码的改写量将大大减少。
理解依赖注入:
    当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例。然而采用依赖注入的方式,创建被调用者的工作不再由调用者来完成,因此叫控制反转,创建被调用者的实例的工作由IOC容器来完成,然后注入调用者,因此也称为依赖注入。
举个有意思的例子(来源于互联网)

假如我们要设计一个Girl和一个Boy类,其中Girl有Kiss方法,即Girl想要Kiss一个Boy,首先问题是Girl如何认识Boy?
在我们中国常见的MM认识GG的方式有以下几种:
A 青梅竹马    B 亲友介绍   C 父母包办
哪一种是最好的?

1.青梅竹马:很久很久以前,有个有钱的地主家的一闺女叫Lily,她老爸把她许配给县太爷的儿子Jimmy,属于指腹为婚,Lily非常喜欢kiss,但是只能kiss Jimmy

  1. public class Lily{  
  2.         public Jimmy jimmy;   
  3.         public Girl()  
  4.         {  
  5.             jimmy=new Jimmy();  
  6.         }  
  7.         public void Kiss()  
  8.         {  
  9.             jimmy.Kiss();  
  10.         }  
  11.     }  
  12.   
  13.     public class Jimmy  
  14.     {  
  15.         public void Kiss()  
  16.         {  
  17.             Console.WriteLine("kissing");  
  18.         }  
  19.     }  

这样导致Lily对Jimmy的依赖性非常强,紧耦合。

2.亲友介绍:经常Kiss同一个人令Lily有些厌恶了,她想尝试新人,于是与Jimmy分手了,通过亲朋好友(中间人)来介绍

  1. public class Lily{  
  2.         public Boy boy;   
  3.   
  4.         public Girl()  
  5.         {  
  6.             boy=BoyFactory.createBoy();  
  7.         }  
  8.         public void Kiss()  
  9.         {  
  10.             boy.Kiss();  
  11.         }  
  12.     }  


亲友介绍,固然是好。如果不满意,尽管另外换一个好了。但是,亲友BoyFactory经常是以Singleton的形式出现,不然就是,存在于Globals,无处不在,无处不能。实在是太繁琐了一点,不够灵活。我为什么一定要这个亲友掺和进来呢?为什么一定要付给她介绍费呢?万一最好的朋友爱上了我的男朋友呢?

 

3.父母包办:一切交给父母,自己不用非吹灰之力,Lily在家只Kiss

  1. public class Lily{  
  2.         public Boy boy;   
  3.         public Girl(Boy boy)  
  4.         {  
  5.             this.boy=boy;  
  6.         }  
  7.         public void Kiss()  
  8.         {  
  9.             this.boy.Kiss();  
  10.         }  
  11.     }  

 

 

Well,这是对Girl最好的方法,只要想办法贿赂了Girl的父母,并把Boy交给他。那么我们就可以轻松的和Girl来Kiss了。看来几千年传统的父母之命还真是有用哦。至少Boy和Girl不用自己瞎忙乎了。这就是IOC,将对象的创建和获取提取到外部。由外部容器提供需要的组件。

在设计模式中我们应该还知道依赖倒转原则,应是面向接口编程而不是面向功能实现,好处是:多实现可以任意切换,我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话,还可以kiss可爱的kitten和慈祥的grandmother

好在.net中微软有一个轻量级的IoC框架Unity,支持构造器注入,属性注入,方法注入如下图所示

具体使用方法如下图所示

  1. using System;  
  2.   
  3. using Microsoft.Practices.Unity;  
  4.   
  5.   
  6. namespace ConsoleApplication9  
  7. {  
  8.     class Program  
  9.     {  
  10.         static void Main(string[] args)  
  11.         {  
  12.             //创建容器  
  13.             IUnityContainer container=new UnityContainer();  
  14.             //注册映射  
  15.             container.RegisterType<IKiss, Boy>();  
  16.             //得到Boy的实例  
  17.             var boy = container.Resolve<IKiss>();  
  18.              
  19.             Lily lily = new Lily(boy);  
  20.             lily.kiss();  
  21.         }  
  22.     }  
  23.   
  24.   
  25.     public interface IKiss  
  26.     {  
  27.         void kiss();  
  28.     }  
  29.       
  30.   
  31.     public class Lily:IKiss  
  32.     {  
  33.   
  34.         public IKiss boy;   
  35.   
  36.         public Lily(IKiss boy)  
  37.         {  
  38.             this.boy=boy;  
  39.         }  
  40.         public void kiss()  
  41.         {  
  42.             boy.kiss();  
  43.             Console.WriteLine("lily kissing");  
  44.         }  
  45.     }  
  46.   
  47.     public class Boy : IKiss  
  48.     {  
  49.         public void kiss()  
  50.         {  
  51.             Console.WriteLine("boy kissing");  
  52.         }  
  53.     }  
  54. }  

如果采用配置文件注册的话

  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <configSections>  
  4.     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>  
  5.   </configSections>  
  6.   <unity>  
  7.     <containers>  
  8.       <container name="defaultContainer">  
  9.         <register type="命名空间.接口类型1,命名空间" mapTo="命名空间.实现类型1,命名空间" />  
  10.         <register type="命名空间.接口类型2,命名空间" mapTo="命名空间.实现类型2,命名空间" />  
  11.       </container>  
  12.     </containers>  
  13.   </unity>  
  14. </configuration>  


配置的后台代码:

  1. UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName)  
  2.             as UnityConfigurationSection;  
  3. configuration.Configure(container, "defaultContainer");  

可以通过方法ResolveAll来得到所有注册对象的实例:
var Instances = container.Resolve<IKiss>();

Martin Fowler在那篇著名的文章《Inversion of Control Containers and the Dependency Injection pattern》中将具体依赖注入划分为三种形式,即构造器注入、属性(设置)注入和接口注入,习惯将其划分为一种(类型)匹配和三种注入:

  • 类型匹配(Type Matching):虽然我们通过接口(或者抽象类)来进行服务调用,但是服务本身还是实现在某个具体的服务类型中,这就需要某个类型注册机制来解决服务接口和服务类型之间的匹配关系;
  • 构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;
  • 属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;
  • 方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。

 

 

我们创建一个控制台程序,定义如下几个接口(IA、IB、IC和ID)和它们各自的实现类(A、B、C、D)。在类型A中定义了3个属性B、C和D,其类型分别为接口IB、IC和ID。其中属性B在构在函数中被初始化,意味着它会以构造器注入的方式被初始化;属性C上应用了DependencyAttribute特性,意味着这是一个需要以属性注入方式被初始化的依赖属性;属性D则通过方法Initialize初始化,该方法上应用了特性InjectionMethodAttribute,意味着这是一个注入方法在A对象被IoC容器创建的时候会被自动调用。

  1. public interface IA { }  
  2.     public interface IB { }  
  3.     public interface IC { }  
  4.     public interface ID { }  
  5.   
  6.     public class A : IA  
  7.     {  
  8.         public IB B { get; set; }  
  9.         [Dependency]  
  10.         public IC C { get; set; }  
  11.         public ID D { get; set; }  
  12.   
  13.         public A(IB b)  
  14.         {  
  15.             this.B = b;  
  16.         }  
  17.         [InjectionMethod]  
  18.         public void Initalize(ID d)  
  19.         {  
  20.             this.D = d;  
  21.         }  
  22.     }  
  23.     public class B : IB { }  
  24.     public class C : IC { }  
  25.     public class D : ID { }  


然后我们为该应用添加一个配置文件,并定义如下一段关于Unity的配置。这段配置定义了一个名称为defaultContainer的Unity容器,并在其中完成了上面定义的接口和对应实现类之间映射的类型匹配。

  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <configSections>  
  4.     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>  
  5.   </configSections>  
  6.   <unity>  
  7.     <containers>  
  8.       <container name="defaultContainer">  
  9.         <register type="UnityDemo.IA,UnityDemo" mapTo="UnityDemo.A, UnityDemo"/>  
  10.         <register type="UnityDemo.IB,UnityDemo" mapTo="UnityDemo.B, UnityDemo"/>  
  11.         <register type="UnityDemo.IC,UnityDemo" mapTo="UnityDemo.C, UnityDemo"/>  
  12.         <register type="UnityDemo.ID,UnityDemo" mapTo="UnityDemo.D, UnityDemo"/>  
  13.       </container>  
  14.     </containers>  
  15.   </unity>  
  16. </configuration>  


最后在Main方法中创建一个代表IoC容器的UnityContainer对象,并加载配置信息对其进行初始化。然后调用它的泛型的Resolve方法创建一个实现了泛型接口IA的对象。最后将返回对象转变成类型A,并检验其B、C和D属性是否是空

  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             UnityContainer container = new UnityContainer();  
  6.             UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;  
  7.             configuration.Configure(container, "defaultContainer");  
  8.             A a = container.Resolve<IA>() as A;  
  9.             if (null!=a)  
  10.             {  
  11.                 Console.WriteLine("a.B==null?{0}",a.B==null?"Yes":"No");  
  12.                 Console.WriteLine("a.C==null?{0}", a.C == null ? "Yes" : "No");  
  13.                 Console.WriteLine("a.D==null?{0}", a.D == null ? "Yes" : "No");  
  14.             }  
  15.         }  
  16.     }  


从如下给出的执行结果我们可以得到这样的结论:通过Resolve<IA>方法返回的是一个类型为A的对象,该对象的三个属性被进行了有效的初始化。这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性B)、属性注入(属性C)和方法注入(属性D)

  a.B == null ? No
 a.C == null ? No
 a.D == null ? No

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

局域网win7计算机如何互访,局域网win7电脑的互访步骤

局域网win7电脑的互访步骤Windows7如何实现局域网内的互访?下面是局域网win7电脑互访的步骤&#xff0c;为大家提供参考。步骤一&#xff1a;同步工作组 不管使用的是什么版本的Windows操作系统&#xff0c;第一步&#xff0c;要保证联网的各计算机的工作组名称一致步骤二&…

服务器自动挂载硬盘,Linux硬盘分区及开机自动挂载

本文以CentOS 6.4为例&#xff0c;查看当前linux服务器分区&#xff1a;df -h查看当前linux服务器硬盘&#xff1a;fdisk -l/dev/sda 第一块硬盘/dev/sdb 第二块硬盘依此类推以/dev/sdb为新增硬盘为例&#xff0c;需要进行以下操作方可正常使用1、分区fdisk /dev/sdb依次输入n&…

GPU Pro2 - 1.Terrain and Ocean Rendering with Hardware Tessellation

最近时间多了起来&#xff0c;准备捡起扔下了的渲染部分的知识。想拜读下GPU Pro系列并且做个笔记&#xff0c;不知道自己能否坚持下来&#xff0c;但愿可以吧。自己能力也有限&#xff0c;写的东西也只是自己的理解&#xff0c;肯定有很多理解不到位甚至错误的地方&#xff0c…

GPU Pro2 - 3.Procedural Content Generation on the GPU

GPU Pro2 - 3.Procedural Content Generation on the GPU 这篇文章着重介绍了基于Brownian 噪声和高度图在GPU中实时生成和渲染无限大地形系统。 Procedural content generation (PCG)程序化生成在许多游戏中已经有广泛应用&#xff0c;从简单的随机物体摆放&#xff0c;到全…

GPU Gems1 - 1 用物理模型进行高效的水模拟(Effective Water Simulation from Physical Models)

该读书笔记大多内容参照了大神浅墨的该篇文章https://zhuanlan.zhihu.com/p/35974789 本章介绍了一种在GPU中模拟和渲染大的水体的系统。它把基本网格的集合波动于动态发现贴图的生成结合起来。 1.1 目标和范围 这章里&#xff0c;我们将由计算简单正弦函数之和开始&#xf…

GPU Gems1 - 2 水刻蚀的渲染

2.1 引言 光线从弯曲的表面反射或折射&#xff0c;因此只聚焦在受光面上的某些区域&#xff0c;于是就产生了刻蚀现象。本文从美学角度出发&#xff0c;不以纯物理的方式计算&#xff0c;使其很容易在大多数图形硬件上实现&#xff0c;效果又十分逼真。 2.2 刻蚀的计算 如果想…

邮箱服务器ip地址白名单,申请SSL证书时如何设置IP地址白名单和邮箱白名单

8月3日消息 在申请SSL证书时&#xff0c;由于您的邮箱可能默认设置或自定义设置了拦截国外邮件&#xff0c;可能会导致您接收不到CA的邮件&#xff0c;给验证、收取证书带来了不便&#xff1b;如果服务器&#xff0c;防火墙也设置了拦截操作&#xff0c;那么即使您按CA要求完成…

GPU Gems1 - 3 Dawn Demo中的皮肤渲染(Skin in the Dawn Demo)

该篇文章参照浅墨的这篇文章&#xff1a;https://zhuanlan.zhihu.com/p/35974789 Dawn是由NVIDIA创建的&#xff0c;用来介绍GeForce FX产品线的演示程序&#xff0c;它说明如何使用可编程的着色技术创建出逼真的人类角色。 最初的Dawn Demo由NVIDIA于2002年发布&#xff0c;…

GPU Gems1 - 5 改良的Perlin噪声的实现

Perlin 噪声 KenPerlin(1985a,2002)KenPerlin(1985a,2002) 定义的噪声函数是最常用的噪声函数&#xff0c;称为 Perlin 噪声。PerlinPerlin 噪声在全部 (x,y,z)(x,y,z) 整形顶点处的参数值都为 00&#xff0c;变化源自各顶点间的梯度向量&#xff0c;然后再进行平滑插值。 计算…

GPU Gems1 - 7 无数波动草叶的渲染

本文部分参照该文章https://zhuanlan.zhihu.com/p/35974789 1.引言 本章介绍了一种灵活的&#xff0c;广泛应用的草模拟。该方案渲染的草不仅生长得自然&#xff0c;也能够逼真地在风中舞动&#xff0c;而且性能很高。 2.概述 首先&#xff0c;需要意识到&#xff0c;对单个…

2003文件服务器迁移2016,服务器2016设置文件共享

服务器2016设置文件共享 内容精选换一换为了保证使用生成的镜像创建的新云服务器可以实现一键式重置密码功能&#xff0c;建议您安装密码重置插件CloudResetPwdAgent&#xff0c;可以应用一键式重置密码功能&#xff0c;给云服务器设置新密码。下载一键式重置密码插件CloudRese…

GPU Gems1 - 8 衍射的模拟

1.什么是衍射 小尺度的表面细节引起反射波彼此干扰&#xff0c;这个现象就是衍射。首先&#xff0c;计算机绘图的大多数表面反射模型都忽略自然光的波动效果。当表面的细节比光的波长&#xff08;约1um&#xff09;大许多时&#xff0c;不存在问题。但对于小尺寸的细节&#x…

GPU Gems1 - 9 有效的阴影体渲染

这章全面讲述了用于实时阴影渲染中常见两种流派之一的阴影体&#xff08;Shadow Volumes&#xff09;技术&#xff0c;又称模板阴影&#xff08;Stencil Shadows&#xff09;技术&#xff0c;重点是得到正确的角度的情形&#xff0c;减少几何图形和填充率的消耗。 简单谈谈阴影…

GPU Gems1 - 10 电影级的光照

本章中介绍了一个的简化的uberlight&#xff08;可理解为“全能光照”&#xff09;实现&#xff0c;此光照shader根据Ronen Barzel(1997,1999)提出的照明模型编写而成。而该模型的超集已由Pixar动画开发&#xff0c;并应用于《玩具总动员》、《怪物公司》、《海底总动员》等一系…

GPU Gems1 - 11 阴影贴图反走样

这章介绍了如何通过邻近百分比过滤方法&#xff08;Percentage-Closer Filtering , PCF&#xff09;有效减少阴影贴图的反走样&#xff0c;并描述了如何实现一个简化版本&#xff0c;并对PCF方法进行了一定改进。关于阴影贴图和PCF技术的一些链接 https://pubweb.eng.utah.edu…

GPU Gems1 - 12 全方位的阴影映射

在这章中&#xff0c;把阴影贴图的思路扩展到正确处理全方位的&#xff08;点&#xff09;光源中&#xff0c;其中包括了实现细节&#xff0c;也涉及到基本硬件能力不足时的低效运行策略。 首先&#xff0c;这篇文章也谈到了在实时计算机图形学中产生可见阴影的两个流行方法是…

GPU Gems1 - 13 使用遮挡区间映射产生模糊的阴影(Generating Soft Shadows Using Occlusion Interval Maps)

这章介绍了一种渲染软阴影的技术&#xff0c;称为遮挡区间映射&#xff08;Occlusion Interval Maps&#xff09;&#xff0c;能够正确地在静态场景中渲染出光源沿着预定路径移动时产生的模糊阴影。之所以叫遮挡区间映射&#xff0c;是因为此算法使用纹理贴图来存储这种光源可见…

粗糙表面的微表面模型——Physically Based Material

关于文章 Microfacet Models for Refraction through Rough Sufaces的一点笔记&#xff0c;欢迎指正。 BSDF BSDF(Bidirectional Sacttering Distribution Function) 描述了光如何在物体表面散射。如果仅仅限制反射或者透射&#xff0c;BSDF经常被称作BRDF或者BTDF,然而BSDF将…

GPU Gems1 - 14 透视阴影贴图(Perspective Shadow Maps: Care and Feeding)

开篇先说&#xff0c;这文章好难懂啊&#xff0c;到现在也没完全弄明白&#xff0c;有大佬的话欢迎指点。这篇大体意思是对Perspective Shadow Maps进行部分优化。GEMS这书这点是真挺蛋疼&#xff0c;很多文章都是对某项技术的优化&#xff0c;那先介绍介绍原来技术嘛&#xff…

GPU Gems1 - 15 逐像素光照的可见性管理

这章讲到了可见性在逐像素渲染光照场景中的作用&#xff0c;也考虑如何使用可见性减少必须渲染的批次数量&#xff0c;从而改善性能。 假设一个非常简单的场景&#xff0c;一个房间&#xff0c;因为房间的不同部位是不同的材质&#xff0c;所以将其分为8个batch&#xff0c;另…