什么是IoC 

IoC是Inversion of Control的缩写,翻译过来为“控制反转”。简单来说,就是将对象的依赖关系交由第三方来控制。在理解这句话之前,我们先来回顾一下IoC的演化。

Ioc前世今生

传统的new class的方式
我们写了一个ChineseSpeaker的类,他有一个SayHello的方法并调用输出控制台:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. ChineseSpeaker chineseSpeaker= new ChineseSpeaker();
  6. chineseSpeaker.SayHello();
  7. }
  8. }
  9.  
  10. public class ChineseSpeaker
  11. {
  12. public void SayHello()
  13. {
  14. Console.WriteLine("你好!!!");
  15. }
  16. }

上面看起来没有任何问题,一切都很好,但是有一天英国演讲者打招呼的话,我们就需要新建了一个BritishSpeaker类:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
  6. //chineseSpeaker.SayHello();
  7.  
  8. BritishSpeaker britishSpeaker = new BritishSpeaker();
  9. britishSpeaker.SayHello();
  10. }
  11. }
  12.  
  13. public class BritishSpeaker
  14. {
  15. public void SayHello()
  16. {
  17. Console.WriteLine("Hello!!!");
  18. }
  19. }
  20.  
  21. //ChineseSpeaker 同上面的代码一样
到目前为止,代码已经暴露出设计原则中要避免的问题:松耦合(loose coupling)。程序中非常依赖实际的class,这导致了:

当出现“日本人”、“印度人”时,我们不得不修改和重新编译代码。当程序代码和逻辑不复杂的时候问题不大,但当程序变大的时候程序猿就苦逼了。

Interface方式

为了避免这种直接依赖关系,我们需要把对象或行为抽象出来一个东西,叫做接口(interface)。它就像电脑中的usb插口,无论是优盘还是鼠标只要插头是usb的我就能使用,从而屏蔽了复杂性。

因此,我们把代码改成:

  1. public interface ISpeak
  2. {
  3. void SayHello();
  4. }
  5.  
  6. public class BritishSpeaker : ISpeak
  7. {
  8. public void SayHello()
  9. {
  10. Console.WriteLine("Hello!!!");
  11. }
  12. }
  13.  
  14. public class ChineseSpeaker : ISpeak
  15. {
  16. public void SayHello()
  17. {
  18. Console.WriteLine("你好!!!");
  19. }
  20. }
因为我们现在把类的实现和功能拆出来了,所以我们可以让客户端动态的来选择谁SayHello
  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
  6. //chineseSpeaker.SayHello();
  7. //BritishSpeaker britishSpeaker = new BritishSpeaker();
  8. //britishSpeaker.SayHello();
  9.  
  10. ISpeak speak;
  11.  
  12. if (args.Length > 0 && args[0] == "Chinese")
  13. {
  14. speak = new ChineseSpeaker();
  15. }
  16. else
  17. {
  18. speak = new BritishSpeaker();
  19. }
  20.  
  21. speak.SayHello();
  22. }
  23. }

这时候我们不知不觉的用到了面向对象六大原则中的依赖倒转原则(DIP),高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口。 好,让我们回到IoC,比较上面的两种写法:

  • 传统的写法类在定义的瞬间就已经决定具体的类型,他的流程是从上到下的
  • 使用interface的写法是在实例化时才决定类的具体类型,也就是用到的时候才会new(),他的流程是new后面来控制的

这时候我们再来看IoC的意思是控制反转,就能大概理解了。传统的写法流程属于从上到下,而interface写法则是由new()其他的类来决定类的实现,因此控制的流程反转了。

DI是什么

利用interface的方式,可以让类在使用的时候再决定由哪个具体类来实现。那该如何实现这种方式呢?这时就有一个新的名称出现了,就是Dependency Injection(依赖注入),简称DI。DI有三种方式,分别是构造函数注入、属性注入、接口注入

构造函数注入

  1. public class Printer
  2. {
  3. private ISpeak _speak;
  4. public Printer(ISpeak speak)//构造函数注入
  5. {
  6. _speak = speak;
  7. }
  8. }
  9.  
  10. class Program
  11. {
  12. static void Main(string[] args)
  13. {
  14. //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
  15. //chineseSpeaker.SayHello();
  16. //BritishSpeaker britishSpeaker = new BritishSpeaker();
  17. //britishSpeaker.SayHello();
  18.  
  19. //ISpeak speak;
  20.  
  21. //if (args.Length > 0 && args[0] == "Chinese")
  22. //{
  23. // speak = new ChineseSpeaker();
  24. //}
  25. //else
  26. //{
  27. // speak = new BritishSpeaker();
  28. //}
  29.  
  30. //speak.SayHello();
  31.  
  32. Printer print;
  33.  
  34. if (args.Length > 0 && args[0] == "Chinese")
  35. {
  36. print = new Printer(new ChineseSpeaker());
  37. }
  38. else
  39. {
  40. print = new Printer(new BritishSpeaker());
  41. }
  42.  
  43. }
  44. }

属性注入

  1. public class Printer
  2. {
  3. public ISpeak Speaker { get; set; }
  4. }
  5.  
  6. class Program
  7. {
  8. static void Main(string[] args)
  9. {
  10. //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
  11. //chineseSpeaker.SayHello();
  12. //BritishSpeaker britishSpeaker = new BritishSpeaker();
  13. //britishSpeaker.SayHello();
  14.  
  15. //ISpeak speak;
  16.  
  17. //if (args.Length > 0 && args[0] == "Chinese")
  18. //{
  19. // speak = new ChineseSpeaker();
  20. //}
  21. //else
  22. //{
  23. // speak = new BritishSpeaker();
  24. //}
  25.  
  26. //speak.SayHello();
  27.  
  28. Printer print = new Printer();
  29. if (args.Length > 0 && args[0] == "Chinese")
  30. {
  31. print.Speaker = new ChineseSpeaker();
  32. }
  33. else
  34. {
  35. print.Speaker = new BritishSpeaker();
  36. }
  37. }
  38. }

接口注入

  1. //接口注入
  2. public interface IPrint
  3. {
  4. void SetSpeaker(ISpeak speak);
  5. }
  6.  
  7. public class Printer : IPrint
  8. {
  9. private ISpeak _speak;
  10. public void SetSpeaker(ISpeak speak)
  11. {
  12. _speak = speak;
  13. }
  14. }
  15.  
  16. class Program
  17. {
  18. static void Main(string[] args)
  19. {
  20. //ChineseSpeaker chineseSpeaker = new ChineseSpeaker();
  21. //chineseSpeaker.SayHello();
  22. //BritishSpeaker britishSpeaker = new BritishSpeaker();
  23. //britishSpeaker.SayHello();
  24.  
  25. ISpeak speak;
  26.  
  27. if (args.Length > 0 && args[0] == "Chinese")
  28. {
  29. speak = new ChineseSpeaker();
  30. }
  31. else
  32. {
  33. speak = new BritishSpeaker();
  34. }
  35.  
  36. Printer printer = new Printer();
  37. printer.SetSpeaker(speak);
  38. }
  39. }

IoC与DI的关系

我的理解是IoC是一种理念,DI则是它的具体实现方式

IoC Container

IoC Container帮我们在项目运行时动态的创建实例,它主要功能如下:

  • 动态创建、注入依赖对象
  • 管理对象生命周期
  • 映射依赖关系

IoC Container技术实现的原理就是“反射(Reflection)”。利用反射动态的创建对象,把依赖关系注入到指定对象中。一般常用的注入方式是构造函数注入和属性注入

Service Locator模式

服务定位模式也是IoC理念的一种实现。实现原理:通过ServiceLocator类提供实现IServiceLocator接口的单例,并负责管理已注册实例的创建和访问。通常结合工厂模式来结合使用。

Service Locator与IoC Container都是IoC的具体实现方式。不同的是Service Locator没有提供管理对象生命周期的功能

.NET 平台下的IoC Container框架

Ninject:  http://www.ninject.org/

Castle Windsor:  http://www.castleproject.org/container/index.html

Autofac:  http://code.google.com/p/autofac/

StructureMap: http://docs.structuremap.net/

Unity:  http://unity.codeplex.com/

Spring.NET: http://www.springframework.net/

结束语

我在学习IoC过程中,学以致用,自己模仿Nject实现了一个IoC Container框架,可以用FluentAPI和xml配置依赖关系,希望对大家有帮助。项目地址:https://github.com/Khadron/Peace

IoC原理及实现的更多相关文章

  1. Java反射机制及IoC原理

    一. 反射机制概念 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义.在java中,只要给定类的名字, 那么就可以通 ...

  2. 【Spring】Spring IOC原理及源码解析之scope=request、session

    一.容器 1. 容器 抛出一个议点:BeanFactory是IOC容器,而ApplicationContex则是Spring容器. 什么是容器?Collection和Container这两个单词都有存 ...

  3. IOC原理分析

    IOC(inversion of control)控制反转 在我们的程序中,要实现某个功能,我们都会用到两个或两个以上的类来协同完成,那么在一个类中,我们就会要有它的合作类的引用,也就是说这个类依赖于 ...

  4. Spring的IOC原理[通俗解释一下]

    Spring的IOC原理[通俗解释一下] 1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图 ...

  5. spring原理案例-基本项目搭建 03 创建工程运行测试 spring ioc原理实例示例

    下面开始项目的搭建 使用 Java EE - Eclipse 新建一 Dynamic Web Project Target Runtime 选 Apache Tomcat 7.0(不要选 Apache ...

  6. Spring之IOC原理及代码详解

    一.什么是IOC 引用 Spring 官方原文:This chapter covers the Spring Framework implementation of the Inversion of ...

  7. 1.IOC原理模拟

    Spring两大核心功能,IOC(Inverse  of  Control)  和 AOP(Aspect-Oriented-Programming) IOC原理模拟: 有这样一个beans.xml: ...

  8. 【SpringBoot】 理解Spirng中的IOC原理

    前言 前文已经介绍了Spring Bean的生命周期,在这个周期内有一个重要的概念就是: IOC容器 大家也知道IOC是Sping 的重要核心之一,那么如何理解它呢,它又是产生什么作用呢?本文就IOC ...

  9. Spring IOC原理补充(循环依赖、Bean作用域等)

    文章目录 前言 正文 循环依赖 什么是循环依赖? Spring是如何解决循环依赖的? 作用域实现原理以及如何自定义作用域 作用域实现原理 自定义Scope BeanPostProcessor的执行时机 ...

  10. Spring IOC 原理深层解析

    1 Spring IOC概念认识 1.1 区别IOC与DI 首先我们要知道IOC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spri ...

随机推荐

  1. How to initialize th rasp berry PI

    WHAT YOU WILL NEED REQUIRED SD Card We recommend an 8GB class 4 SD card – ideally preinstalled with ...

  2. 数据库字段名称转java字段名称

    /** * * @Title: changeToJavaFiled * @Description: TODO(将数据库中带下划线的字段转换为Java常用的驼峰字段) * @param @param f ...

  3. zabbix_sender高效模式

    1.zabbix_sender介绍 zabbix获取key值有超时时间,如果自定义的key脚本一般需要执行很长时间,这根本没法去做监控,获取数据有超时时间,如果一些数据需要执行比较长的时间才能获取的话 ...

  4. hibernate学习系列-----(3)Session 缓存和持久化生命周期以及Session 基本操作

    Session缓存原理 为了能够在控制台更好的看到我们的hibernate干了些什么,可以在hibernate.cfg.xml文件中写入如下配置: <!-- print all generate ...

  5. python——内置对象

    python的内置对象 对象类型 常量示例/用法 Number(数字) 3.14159, 1234, 999L 3+4j String(字符串) 'spam', "guido's" ...

  6. TP框架中/ThinkPHP/Library/Think/Storage/Driver/File.class.php 错误

        /ThinkPHP/Library/Think/Storage/Driver/File.class.php LINE: 48错误 这是一个将windows下运行正常的ThinkPHP框架移到L ...

  7. Mac环境下反编译apk

    0,工具汇总 我们反编译apk主要使用下面三个工具 apktool:用于获取资源文件 dex2jar:获取源文件jar包 JD-GUI:反编译源文件jar包查看源码 找这些工具时折腾了我点时间.如今把 ...

  8. 【Excle】如何隐藏数据透视表中的错误值

    如下:数据透视表出现错误 怎么解决呢 步骤 方法① 单击数据透视表任意单元格→数据透视表工具→分析→选项→勾选"对于错误值显示"→确定 方法② 右键→数据透视表选项(同样可以修改)

  9. 转Postman请求Https接口

    转自:https://blog.csdn.net/ONS_cukuyo/article/details/79172242 单向认证 像平常一样访问就行,无需做任何处理,只需要把http://变成htt ...

  10. POJ 1731 Orders(STL运用)

    题目地址:POJ 1731 这题能够直接用STL函数做,非常轻松..next_permutation函数非常给力.. 代码例如以下: #include <algorithm> #inclu ...