现在的位置: 首页 > 综合 > 正文

对ioc和di的理解

2018年05月22日 ⁄ 综合 ⁄ 共 2947字 ⁄ 字号 评论关闭

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{
   private C comp;
  ......
}

  实现comp实例有两种途径:单态工厂模式和Ioc。

工厂模式实现如下:

public class B{
   private C comp;
  private final static MyFactory myFactory = MyFactory.getInstance();

  public B(){
    this.comp = myFactory.createInstanceOfC();

  }
   public void someMethod(){
    this.comp.sayHello();
  }
  ......
}

特点:

  • 每次运行时,MyFactory可根据配置文件XML中定义的C子类实现,通过createInstanceOfC()生成C的具体实例。

使用Ioc依赖性注射( Dependency Injection )实现Picocontainer如下,B类如同通常POJO类,如下:

public class B{
   private C comp;
  public B(C comp){
    this.comp = comp;
   }
   public void someMethod(){
    this.comp.sayHello();
   }
  ......
}

假设C接口/类有有一个具体实现CImp类。当客户端调用B时,使用下列代码:

public class client{
   public static void main( String[] args ) {
    DefaultPicoContainer container = new DefaultPicoContainer();
    container.registerComponentImplementation(CImp.class);
    container.registerComponentImplementation(B.class);
    B b = (B) container.getComponentInstance(B.class);
    b.someMethod();
   }
}

  因此,当客户端调用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,就像提供了显卡插槽。

【上篇】
【下篇】

抱歉!评论已关闭.