1,什么叫控制反转,谁控制谁,控制什么,如何反转?
2,以前的控制是什么样的?
3,控制反转后事什么样的?
4,这样有什么好处?
5,有几种实现?
6,每种实现应该在什么情况下使用?
7,工厂模式是IOC的一类吗?
8,一个容易理解的比喻
9,如果说IOC是对对象生命周期的管理的话,那么servlet容器管理servlet算不算是一种IOC应用?
回答1:
所谓控制反转,我一直有两个疑问,第一个有关“控制”:谁控制谁?控制什么?第二个有关“反转”:因为我理解“反转”这个词表示“事情颠倒过来”,也就是如果之前是A控制B,那么现在B控制A了,这才叫反转。
经过查询,这几个疑问有了一些理解。说控制什么,是指控制对象的创建以及对象的生命周期。如果没有IOC,则是对象直接控制对象,拿fowler的例子说:
class MovieLister...
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
类MovieLister直接控制ColonDelimitedMovieFinder的创建以及生命周期。这样做的坏处就是如果finder的实现类变了,就不得不修改MovieLister类。依赖关系是MovieLister依赖于MovieFinder接口以及ColonDelimitedMovieFinder类:
如果要解决这个问题,就要让MovieLister不要依赖于具体的实现类比如ColonDelimitedMovieFinder,而只依赖实现类所实现的接口MovieFinder。这里有个设计模式叫做Dependency Inversion(依赖反转),需要再看一看headfirst,工厂模式就是遵循了这个思想。如果用工厂模式解决这个问题,很有可能是这样:
class MovieLister...
private FinderFactory finderFactory; //如何实例化这个factory
private MovieFinder finder;
public MovieLister() {
finder = finderFactory.instance();
}
会发现,即使用了工厂模式,确定具体的工厂实现类同样让人烦恼,似乎和以前确定具体的finder是一样的。那么应该如何解决呢?一个方法是:让其它类实例化这个具体类,然后再注入进来。
当然,用反射机制可以解耦。比如把具体的类名存在一个配置文件中,在实例化时读这个配置文件,取出类名,用反射机制实例化具体对象。但是这样做给程序设计者造成了很大的负担。
如图,MovieLister不再依赖于具体实现类,而只是依赖于接口。创建和控制具体对象的转到了Assembler负责。至此,对象的创建和生命周期的控制,得到了反转。(实际上,我觉得反转这个词不如转换容易理解)
回答2:
以前是用户自己控制对象的生命周期。
回答3:
遵循IOC后,对象的生命周期的控制从用户代码中抽离出来,在Assembler里控制,然后以某种方式注入到用户代码中。
回答4:
使用户代码和具体对象的创建相分离,解决了耦合度,使具体对象可以在用户代码外部决定,以类似plugin的方式灵活注入。用户的业务代码以及要注入的依赖对象都相对独立,可以在其它地方使用。
回答5:
依赖注入有3种实现方式,构造方法注入,set方法注入以及接口注入。其中前两种是比较常见的。
回答6:
关于构造方法注入和set方法注入,在什么时候试用,在fowler和Johnson的文章里都有解释,有一些没有理解,但大致是:当参数较多,有继承关系的时候,尽量用SET注入。当对象简单,参数少,就用构造子注入。picocontainer是构造子注入的支持者,而一般的框架都会同时支持这两中注入方式。
回答7:
在这篇文章里解释的很清楚:http://www.diybl.com/course/3_program/java/javashl/2008520/117110.html
工厂模式和Ioc
假设有两个类B 和 C:B作为调用者,C是被调用者,在B代码中存在对C的调用:
public class B{ |
实现comp实例有两种途径:单态工厂模式和Ioc。
工厂模式实现如下:
public class B{ public B(){ } |
特点:
- 每次运行时,MyFactory可根据配置文件XML中定义的C子类实现,通过createInstanceOfC()生成C的具体实例。
使用Ioc依赖性注射( Dependency Injection )实现Picocontainer如下,B类如同通常POJO类,如下:
public class B{ |
假设C接口/类有有一个具体实现CImp类。当客户端调用B时,使用下列代码:
public class client{ |
因此,当客户端调用B时,分别使用工厂模式和Ioc有不同的特点和区别:
主要区别体现在B类的代码,如果使用Ioc,在B类代码中将不需要嵌入任何工厂模式等的代码,因为这些工厂模式其实还是与C有些间接的联系,这样,使用Ioc彻底解耦了B和C之间的联系。
使用Ioc带来的代价是:需要在客户端或其它某处进行B和C之间联系的组装。
所以,Ioc并没有消除B和C之间这样的联系,只是转移了这种联系。
这种联系转移实际也是一种分离关注,它的影响巨大,它提供了AOP实现的可能。
回答8:
http://topic.csdn.net/t/20060508/23/4737423.html
没有IOC,就像集成显卡;有了IOC,就像提供了显卡插槽。