引言:html
项目中遇到关于IOC的一些内容,由于和正常的逻辑代码比较起来,IOC有点反常。所以本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来的。本文目的两个,一是记录学习过程,以便未来温故;二是请大牛对小弟指点一二。编程
概念:小程序
控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转通常分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较普遍。-百度百科。设计模式
简单实例:框架
下面编写使用IOC实现的简单实例,以便你们对IOC有个初始的概念。功能是输入字符串格式的日志,代码以下:编程语言
接口ILogger和具体的Logger类:ide
public interface ILogger { void Log(string msg); } public class Logger : ILogger { public virtual void Log(string msg) { Console.WriteLine("msg is {0}", msg); } }
常规的调用方式:函数
ILogger logger = new Logger(); logger.Log("good");
使用IOC模式的客户端调取方式:post
添加using Microsoft.Practices.Unity;学习
IUnityContainer container = new UnityContainer(); container.RegisterType<ILogger, Logger>(); ILogger logger = container.Resolve<ILogger>(); logger.Log("good");
结果以下:
介绍经常使用的概念:依赖、依赖倒置、控制反转、依赖注入。
平常编码过程当中,新建一个类,进而new对象进而进行相关的业务逻辑,例以下面实例,用户播放媒体文件:
public class OperationMain { public void PlayMedia() { MediaFile _mtype = new MediaFile(); Player _player = new Player(); _player.Play(_mtype); } } public class Player { public void Play(MediaFile file) { Console.WriteLine(file.FilePath); } } public class MediaFile { public string FilePath { get; set; } }
从上文能够看出代码的耦合度过高了,若是有新的需求,须要改动的地方太多了,那么使用依赖倒置原则来下降耦合度。
依赖倒置原则:
高层模块不该该依赖于低层模块,二者应该依赖于抽象;
抽象不该该依赖于具体,具体应该依赖于抽象;
public class OperationMain { public void PlayMedia() { IMediaFile _mtype = new MediaFile(); IPlayer _player = new Player(); _player.Play(_mtype); } } public interface IPlayer { void Play(IMediaFile file); } public class Player : IPlayer { public void Play(IMediaFile file) { Console.WriteLine(file.FilePath); } } public interface IMediaFile { string FilePath { get; set; } } public class MediaFile : IMediaFile { public string FilePath { get; set; } }
控制反转:
控制反转(IoC),它为相互依赖的组件提供抽象,将依赖(低层模块)对象的得到交给第三方(系统)来控制,即依赖对象不在被依赖模块的类中直接经过new来获取。
控制反转IoC是Inversion of Control的缩写,是说对象的控制权进行转移,转移到第三方,好比转移交给了IoC容器,它就是一个建立工厂,你要什么对象,它就给你什么对象,有了IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,经过IoC容器来创建它们之间的关系。
依赖注入:
依赖注入,控制反转(IoC)一种重要的方式,就是将依赖对象的建立和绑定转移到被依赖对象类的外部来实现。
依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
public class OperationMain { IMediaFile _mtype; IPlayer _player; public OperationMain(IPlayer player, IMediaFile mtype) { _player = player; _mtype = mtype; } public void PlayMedia() { _player.Play(_mtype); } }
调用方式:
static UnityContainer container = new UnityContainer(); static void init() { container.RegisterType<IPlayer, Player>(); container.RegisterType<IMediaFile, MediaFile>(); } static void Main(string[] args) { init(); OperationMain op1 = container.Resolve<OperationMain>(); op1.PlayMedia(); //普通方式 OperationMain op2 = new OperationMain(new Player(), new MediaFile()); op2.PlayMedia(); }
注入方式:
依赖注入的方式有不少:
编写实例说明依赖注入的方式:
接口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"); }
运行结果:
自我理解:
依赖注入,从深层次上仍是不能理解其本质。此处介绍其用法,大体可分为三步:
一、定义一个container,
IUnityContainer container = new UnityContainer();
二、接口和实现类的注册,
container.RegisterType<ILogger, Logger>();
三、生成对象
ILogger logger = container.Resolve<ILogger>();
完
网上摘抄:
1、
大多数面向对象编程语言,在调用一个类的时候,先要实例化这个类,生成一个对象。
若是你在写一个类,过程当中要调用到不少其它类,甚至这里的其它类,也要“依赖”于更多其它的类,那么能够想象,你要进行多少次实例化。
这就是“依赖”的意思。
依赖注入,全称是“依赖注入到容器”, 容器(IOC容器)是一个设计模式,它也是个对象,你把某个类(无论有多少依赖关系)放入这个容器中,能够“解析”出这个类的实例。
因此依赖注入就是把有依赖关系的类放入容器(IOC容器)中,而后解析出这个类的实例
2、
假若有一个 船(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 或者特定的对象中,并实现动态的注入。
推荐两篇至关精彩实用的博文:
引用: