引言:
项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常。因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来的。本文目的两个,一是记录学习过程,以便将来温故;二是请大牛对小弟指点一二。
概念:
控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。-百度百科。
简单实例:
下面编写使用IOC实现的简单实例,功能是输入字符串格式的日志。代码如下:
接口ILogger和具体的Logger类:
public interface ILogger { void Log(string msg); } public class Logger : ILogger { public virtual void Log(string msg) { Console.WriteLine("msg is {0}", msg); } }
使用IOC模式的客户端调取方式:
添加using Microsoft.Practices.Unity;
IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, Logger>(); ILogger logger = container.Resolve<ILogger>(); logger.Log("good");
结果如下:
注入方式:
依赖注入的方式有很多:
- 构造器注入(Constructor Injection):Ioc容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,Ioc容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;
- 属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,Ioc容器会自动初始化该属性;
- 方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,Ioc容器会自动调用该方法
编写实例说明依赖注入的方式:
接口IA,IB,IC,ID和具体类A,B,C,D。
public interface IA{ } public interface IB{} public interface IC { } public interface ID { } public class A : IA { public IB B { get; set; } [Dependency] public IC C { get; set; } public ID D { get; set; } public A(IB b) { this.B = b; } [InjectionMethod] public void Initialize(ID d) { this.D = d; } } public class B : IB{} public class C : IC { } public class D : ID { }
客户端调用方式:
IUnityContainer container = new UnityContainer(); container.RegisterType<IA, A>(); container.RegisterType<IB, B>(); container.RegisterType<IC, C>(); container.RegisterType<ID, D>(); A a = container.Resolve<IA>() as A; if (null != a) { Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No"); Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No"); Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No"); }
运行结果:
自我理解:
依赖注入,从深层次上还是不能理解其本质。此处介绍其用法,大致可分为三步:
1、定义一个container,
IUnityContainer container = new UnityContainer();
2、接口和实现类的注册,
container.RegisterType<ILogger, Logger>();
3、生成对象
ILogger logger = container.Resolve<ILogger>();
完
网上摘抄:
一、
大多数面向对象编程语言,在调用一个类的时候,先要实例化这个类,生成一个对象。
如果你在写一个类,过程中要调用到很多其它类,甚至这里的其它类,也要“依赖”于更多其它的类,那么可以想象,你要进行多少次实例化。
这就是“依赖”的意思。
依赖注入,全称是“依赖注入到容器”, 容器(IOC容器)是一个设计模式,它也是个对象,你把某个类(不管有多少依赖关系)放入这个容器中,可以“解析”出这个类的实例。
所以依赖注入就是把有依赖关系的类放入容器(IOC容器)中,然后解析出这个类的实例
二、
假如有一个 船(C)类 ,一个 桨(J) 类,
class C{ J j = new J() ; }
如果船要干什么事,肯定需要浆的参与。所以是十分 “依赖”浆;
出了需求需要重构:这时候我们需要控制浆的长度为10在构造方法中。我们需要这么写;
class C{ J j = new J(10) ; }
一个特性需要修改浆构造方法,又需要修改船其中的new J()方法。这时候就设计者就思考,为什么我们加入一个特性需要更改两个类中代码(这也就是耦合度高)!
所以我们要解耦要依赖注入;
常用解耦方式:
构造方法注入
如下:我重构代码的时候在也不用看哪里的浆还是短的了!因为船构造方法依赖了浆。任你浆怎么设计,我用的时候传一个浆进来即可。(下层依赖上层,用的时候传入,而不是针对下层去修改)
class C{ J j ; public c(J j) { this.j = j; }; }
工厂模式注入
工厂模式 Human 人 去注入; 工厂类如下
Class Human { J j =new J(); J getJ() { return j ; } }
此时如下:不管你怎么改浆,改成100米与船都无关,他只要依赖Human,
一千个船修改浆需求我只修改Human类中方法便可。(核心业务逻辑需要依赖的类实例化交给第三方类来实现注入。)
Class C { J j ; Human h = new Human; j=Human.getJ(); }
框架注入(本质还是工厂设计模式的具体实现)
本质也是第三方依赖注入,但是这个第三方可以脱离类。将对象依赖映射信息存储在容器一般为.xml 或者特定的对象中,并实现动态的注入。
引用: