论坛首页 Java企业应用论坛

我对IoC/DI的理解

浏览 39403 次
该帖已经被评为精华帖
作者 正文
   发表时间:2012-04-01  
liguocai2009 写道
整篇文章我看了两遍,不得不大赞精彩!有一行,我不理解,文章也没有着重讲
引用
容器:提供组件运行环境,管理组件声明周期(不管组件如何创建的以及组件之间关系如何装配的);


能不能讲讲“提供组件运行环境,管理组件声明周期”具体表现为什么,做了什么工作?因为我看完文章之后,
感觉IOC容器好像就仅仅是这样:
1 建立一个xml,描述类的创建和类之间的关系。
2 IOC容器的main函数,读取xml,通过反射技术建立对象。应用程序在IOC容器的帮助下,无需关心类的创建,就可以轻松地获取到类实例。

于是我想,“提供组件运行环境,管理组件声明周期”究竟有什么用?为什么要有这两个功能?



这个要联系具体使用的容器了

你可以下载这个PPT看看 http://sishuok.com/forum/posts/list/1080.html
0 请登录后投票
   发表时间:2012-04-01   最后修改:2012-04-01
控制反转,我个人简单了理解就是:接口 + 配置.
两者缺一不可, 如果引用类型是实现类而不是接口,这样控制很难反转. 如果不用配置来指定实现类,控制也很难反转.
初学者往往容易被"专业名词"吓到,呵呵.
0 请登录后投票
   发表时间:2012-04-01   最后修改:2012-04-01
引用
迪米特法则(最少知识原则):不知道依赖的具体实现,只知道需要提供某类服务的对象(面向接口编程),松散耦合,一个对象应当对其他对象有尽可能少的了解,不和陌生人(实现)说话

迪米特法则跟面向接口编程不能混为一谈,它指的是不要和“朋友”外的第三者说话,而不是和谁说话,关键点是第三者。
说下个人感悟:IOC/DI根本就不是什么新鲜事物,本质上只是依赖倒置原则的一种更加彻底的体现,依赖于抽象,不依赖于具体,固定不变的逻辑骨架,隔离变化。多态+反射就是抽象。它与普通的面向接口编程唯一的区别就是配置文件的界入把变化完全移到了程序之外。但只是把变化隔离地更加彻底,本质上没有任何区别,依然是依赖倒置。
0 请登录后投票
   发表时间:2012-04-01  
hyj1254 写道
引用
迪米特法则(最少知识原则):不知道依赖的具体实现,只知道需要提供某类服务的对象(面向接口编程),松散耦合,一个对象应当对其他对象有尽可能少的了解,不和陌生人(实现)说话

迪米特法则跟面向接口编程不能混为一谈,它指的是不要和“朋友”外的第三者说话,而不是和谁说话,关键点是第三者。
说下个人感悟:IOC/DI根本就不是什么新鲜事物,本质上只是依赖倒置原则的一种更加彻底的体现,依赖于抽象,不依赖于具体,固定不变的逻辑骨架,隔离变化。多态+反射就是抽象。它与普通的面向接口编程唯一的区别就是配置文件的界入把变化完全移到了程序之外。但只是把变化隔离地更加彻底,本质上没有任何区别,依然是依赖倒置。



(面向接口编程):此处不严谨,应该是面向抽象编程。

一、DIP 依赖倒置原则
  1、这个得要从结构化编程说起,在结构化编程中一般都是自上而下开发,这样的问题是:
     上层组件依赖底层组件,且一般依赖于具体实现,这样就很难更换实现(即改变实现策略)

  2、而在面向对象的世界里,一般都是分布式开发,我们需要做到的是我有A组件需要B类型的服务,对于B是如何实现的我不关心。


二、这就引出了依赖倒置原则:
    //代码1
    //A依赖于B服务
    class A{//上层组件
       B b = new B();  //底层组件 
    }
    class B{
    }

    这段代码问题是上层组件依赖于底层组件,且依赖于具体实现。

    但,我们应该是:
     上层组件不依赖于底层的具体组件实现,而是依赖于抽象,即我需要什么服务(通过接口/抽象类表达)
      而且我们的抽象不应该依赖于具体实现,应该是具体实现依赖于抽象(面向抽象编程能很容易的更换实现策略)

      也就是说应该如下形式:
      //代码2
      //A依赖于BInterface类型的服务
      class A{ //上层组件
          BInterface b;  //底层组件需要实现的抽象
          public void setB(BInterceface b) { //设置依赖关系
               this.b = b;
          }
      }
      class B inplements BInterface{} //具体实现依赖于抽象

      发展到这我们就可以非常容易的进行分布式开发,定义服务(抽象),大家只需声明我需要××类型的服务即可。

      但这样,很多开发人员可能并不能很好的进行实践,毕竟是原则,可能违反。

    
      此时有一种叫IoC的原则出来了,它是实现DIP的一种更加具体化的方式。

三、IoC控制反转,即控制权的转移。
     首先如代码1,A依赖于B,B具有控制权(B是老大,B的变会引起A变【即如B实现换成C实现,A可能就得变】),即底层有控制权(上层依赖于底层,且依赖于具体实现)
    
     而代码2,把控制权从底层转移到上层,即发生了控制权的转移(底层依赖于上层,底层实现依赖于上层抽象),是一种IoC,发生了控制权转移后,我们面临的问题是如何装配上层和底层组件的关系,此时A组件通过暴露setter方法(setB),说自己需要什么类型的服务。

四、因此又提出DI(依赖注入)
  组件通过setter方法(构造器/setter/接口等)将抽象暴露出来后,需要有人来装配组件和底层组件之间的关系;
  此时有一个叫装配器的对象负责帮我们装配组件之间的依赖关系(将底层组件装配到上层组件中)。

  即DI又帮助IoC实现了将底层组件装配到上层组件。

如我们常用的工具类:
    Arrays.sort(T[] a, Comparator<? super T> c)

   Arrays和 Comparator都是上层组件,Comparator是底层组件,底层组件依赖于上层组件,而且是抽象不依赖于实现,实现依赖于抽象。

   此时控制权从底层转移到高层,而且我们需要第三方组件(这个就是装配器),来装配高层组件和底层组件之间的关系。

以上个人见解,不妥地方请指正!
0 请登录后投票
   发表时间:2012-04-01  
hyj1254 写道

迪米特法则跟面向接口编程不能混为一谈

这一点是,我说错了。

hyj1254 写道

它指的是不要和“朋友”外的第三者说话,而不是和谁说话,关键点是第三者。

即尽量少的和别的类产生依赖关系,这样的话耦合就低了,如果实在想说话,可以通过你说的朋友(如中介、门面)来说话。

谢谢指正。
0 请登录后投票
   发表时间:2012-04-01  
hyj1254 写道

迪米特法则(最少知识原则):不知道依赖的具体实现,只知道需要提供某类服务的对象(面向接口编程),松散耦合,一个对象应当对其他对象有尽可能少的了解,不和陌生人(实现)说话


我此处表达的是另一个面:

不知道依赖的具体实现,只知道需要提供某类服务的对象(面向抽象编程),松散耦合,一个对象应当对其他对象有尽可能少的了解,不和陌生人(实现)说话

组件----抽象-----实现 (上边的这句话我想表达的是这个含义)

组件----门面----其他组件

组件----中介----门面

0 请登录后投票
   发表时间:2012-04-02  
ecustz 写道
希望楼主多写点这方面的帖子,学习了!!!


以上都是我自己的理解,大家一起讨论,可能我的理解也是错的!
0 请登录后投票
   发表时间:2012-04-06  
一直关注楼主的博客,内容很不错,学习了
0 请登录后投票
   发表时间:2012-04-06  
zhua12 写道
一直关注楼主的博客,内容很不错,学习了

谢谢支持
0 请登录后投票
   发表时间:2012-04-16  
DI实际上是把对象的创建过程/逻辑从使用/业务逻辑中分离了出来。通常来说,创建只要最开始做一次,然后就与后面的使用没有关系了。于是抽取出来符合“把变化速率一样的逻辑放在一起”这条原则。同时,由于抽取了创建逻辑,具体的对象依赖关系(对象图)也就不需要应用代码来维护了(交给DI容器了)。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics