IOC和Dependency Injection

原创 2004年10月26日 00:26:00

 最近网上这两个名词出现频率很高,于是抱着学习的态度读了Martin Flower的大作以及一些相关的文章,将心得与大家分享。

 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

介绍

其实IOC模式并不是什么新的东西,它是一种很普遍的概念(或者说结构),GoF中的Template Method 就是IOC的结构。顾名思义,IOC即控制反转。著名的好莱坞原则:“Don’t Call us, We will call you”,以及Robert C. Martin在其敏捷软件开发中所描述的依赖倒置原则(Dependency Inversion Principle, DIP)都是这一思想的体现。Dependency InjectionMartin FlowerIOC模式的一种扩展的解释,下面我们从一个简单的实例开始。

 

考虑一个Button来控制Lamp的开和关。

拿到这个功能,我不假思索的画出了如下的类图,并写下了代码。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

 

public class Button {

       private Lamp lnkLamp;

       public void poll() {

              lnkLamp.Turnon();

       }

}

但是马上发现这个设计的问题,Button类直接依赖于Lamp类,这个依赖关系意味着当Lamp类修改时,Button类会受到影响。此外,想重用Button类来控制类似与Lamp的另外一个对象则是不可能的。即Button控制Lamp,并且只能控制Lamp

显然,我违反了“高层模块不应该依赖于底层模块,两者都应该依赖于抽象;抽象不应该依赖于具体实现,细节应该依赖于抽象” 这一原则(DIP原则)。

考虑到上述问题,自然地想到应该抽象出一个接口,来消除ButtonLamp的依赖,于是设计如下:


    这样,我们倒置了
ButtonLamp的依赖关系,使得Lamp依赖于SwitchableDevice接口,SwitchableDevice并没有依赖于Button类,任何知道如何操纵该接口的对象都可以控制Lamp。同时Button不只是可以控制Lamp,还可以控制同样实现SwitchableDevice接口的如ComputerCell Phone等等。回头想想,这种做法好像似曾相识,拍拍脑袋,哦!这不是GoF策略(Strategy)模式吗?!正是,不经意间我就应用了设计模式(有点得意哦~~~~)。

现在再来考虑一个问题,刚才的做法虽然倒置了依赖关系,但是如果将Button作为一个应用程序来控制Lamp或者同样实现SwitchableDeviceComputerCell Phone等,则代码可能如下:

public class Button {

private SwitchableDevice lnkLamp;

public Button(){

    lnkLamp= new Lamp();

}

}

也就是说ButtonLamp之间仍然存在《creates》这样的依赖关系。

为了解除这种依赖关系,首先看GoF能作些什么。显然,这个地方应该用Factory模式,将对象的创建交给Factory Class来处理,这样虽然解开了Lamp组件与我们应用程序Button之间的耦合关系,但是组件的创建仍然是显式的(explicitly),在组件更改时仍需要重新编译。

另外,通过一个ServiceLocatorlook up实现类也是一种解除耦合的办法,看到这儿,你不禁会想EJB不就是这么实现的嘛,U are Right! Rod Johnson 在其大作J2EE without EJB中称这种方式为Dependency Look up,但这种方式也有其弊端,比如无法脱离容器环境,以及不利于Unit test等。

Don’t Call us, We will Call you”,这个原则启示我们应该换一个思路,不应该在应用类中创建具体对象的实例,而是应该将具体对象实例的创建插入(plug)或者说注射(inject)到应用类中,这大概是依赖注射名称的由来吧。

这种实现方式需要在应用类以及调用组件之间建立一个assembler来解除两者之间的依赖,看起来与前面的方式没有太大区别,来看一下结构:


    仔细查看会发现还是有比较大的不同,依赖关系是相反的,也就是说这个过程中依然倒置了依赖关系。
Lamp通过Assembler将其创建过程注射到了Button中,从而消除了两者之间的耦合,增加了灵活性。

下面我们看一下具体的实现,在PicoContainer以及Spring中有着其不同的实现,分别代表了两种类型的Dependency Injection, Constructor Injection Setter Injection

private MutablePicoContainer configureContainer() {

        MutablePicoContainer pico = new DefaultPicoContainer();

        pico.registerComponentImplementation(SwitchableDevice.class, Lamp.class);

        pico.registerComponentImplementation(Button.class);

        return pico;

}

然后可以通过MutablePicoContainergetComponentImplementation方法获得实现类,调用其poll方法控制Lamp的开关,这样一来,两者之间的耦合通过PicoContainer提供的Assembler完全消除了。

Spring则通过一个XML格式的配置文件,将两者联系起来,使用时,通过ApplicationContext获得Button Bean,再调用其方法实现,同样也消除了耦合关系。

 

后面我将会关注SpringIOC以及AOP的实现,学习的同时会将心得以Blog的形式与大家分享。

 

C++ IOC

Fruit is a dependency injection framework for C++, loosely inspired by the Guice framework for Java...
  • dajijidanaizi
  • dajijidanaizi
  • 2016-04-12 09:52:19
  • 855

Scala中Dependency Injection

依赖注入是指 依赖对象的创建,由第三方完成,而不是被依赖对象,我们将这种控制关系的转移,称为依赖注入或者控制反转。在spring 的ioc 就是经典的案例。通过配置文件和反射机制,将依赖对象的创建交给...
  • pzw_0612
  • pzw_0612
  • 2015-07-19 23:35:45
  • 1044

IoC 容器和Dependency Injection 模式

  • 2007年05月30日 08:52
  • 69KB
  • 下载

1.2.3依赖注入容器

【2017.12.30: 1.原博客 依赖注入(Dependency Injection)模式 大概的意思有,写得较垃圾:不流畅,例子不好。 2.不再将DI称为一种模式,而仅仅视为工具箱;强调 依...
  • yqj2065
  • yqj2065
  • 2013-01-16 16:39:44
  • 25385

Atitit。如何实现dip, di ,ioc  ,Service Locator的区别于联系

Atitit。如何实现dip, di ,ioc  ,Service Locator的区别于联系   1. Dip原则又来自于松耦合思想方向1 2. 要实现dip原则...
  • attilax
  • attilax
  • 2016-09-16 16:55:12
  • 356

DotNetCore跨平台~一起聊聊Microsoft.Extensions.DependencyInjection

写这篇文章的心情:激动 Microsoft.Extensions.DependencyInjection在github上同样是开源的,它在dotnetcore里被广泛的使用,比起之前的autof...
  • hongjienuan7212
  • hongjienuan7212
  • 2017-10-11 18:08:21
  • 149

Martin Fowler的IoC 容器和Dependency Injection 模式 摘要

spring等轻量级容器能够帮助开发者将来自不同项目的组件组装成为一个内聚的应用程序.。在它们的背后有着同一个模式,这个模式决定了这些容器进行组件装配的方式。人们用一个大而化之的名字来称呼这个模式:“...
  • soleghost
  • soleghost
  • 2005-07-13 23:33:00
  • 7104

IoC容器和Dependency Injection模式---Martin Fowler著,透明翻译

关于IoC容器和DI模式的经典文章。地址:http://gigix.blogdriver.com/gigix/inc/DependencyInjection.pdf...
  • surprisesdu
  • surprisesdu
  • 2006-05-19 16:53:00
  • 1449

Dependency Injection

  • 2011年03月14日 16:31
  • 12.06MB
  • 下载

依赖注入&控制反转 oC 容器和Dependency Injection 模式

撰文/Martin Fowler 编译/透明Java 社群近来掀起了一阵轻量级容器的热潮,这些容器能够帮助开发者将来自不同项目的组件组装成为一个内聚的应用程序。在它们的背后有着同一个模式,这个模式决定...
  • suncheng_hong
  • suncheng_hong
  • 2006-11-09 14:02:00
  • 5011
收藏助手
不良信息举报
您举报文章:IOC和Dependency Injection
举报原因:
原因补充:

(最多只允许输入30个字)