`
darrenzhu
  • 浏览: 782199 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

依赖倒置原则(DIP),依赖注入(DI),控制反转(IoC)

阅读更多
原文链接:http://www.importnew.com/1019.html

控制反转(Inversion of Control,IoC)
对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。在没有控制反转时,对象A如果需要调用对象B的方法,那么对象A要自己创建对象B,有了IoC后,容器负责创建B并注入A。

Question:
对于依赖倒置原则(Dependency Inversion Principle,DIP),依赖注入(Dependency Injection,DI)和控制反转(Inversion of Control,IoC)容器,你是怎么理解的?

Answer:
依赖倒置原则(Dependency Inversion Principle, DIP)。这个设计准则某种程度上和依赖注入模式有些关联。DIP的出发点是:在应用开发中,高层模块不应当直接依赖低层模块。DIP并不意味着依赖注入。这个准则并没有讲到高层模块如何知道调用哪个低层模块。不过这一点通过实现工厂模式接口可以间接获知,或者通过类似Spring框架、Pico容器、Guice或者Apache HiveMind之类的loC容器实现依赖注入从而得知高层模块调用的具体哪个低层模块。



DIP意味着:

高层模块不应当依赖低层模块,它们都应当依赖抽象。
抽象不应该依赖具体实现。具体实现应该依赖抽象。
应用这个准则后,高层模块并不直接同低层模块交互,而是通过一个抽象层来跟低层模块进行交互。这使得需求变更后增加的成本更加灵 活可控。这里有些实现DIP的示例代码片段。

首先定义抽象层:
package principle_dip2;
public interface AnimalHandler {
    public abstract void handle( );
}
package principle_dip2;
public interface AnimalHelper {
    public abstract void help( );
}
接着是依赖于抽象类而非具体实现的高层代码。

package principle_dip2;
public class CircusService {
    AnimalHandler handler;
    public void setHandler(AnimalHandler handler) {
        this.handler = handler;
    }
    public void showStarts( ) {
        //code omitted for brevity
        handler.handle( );
    }
}
package principle_dip2;
public class TigerHandler implements AnimalHandler{
    AnimalHelper helper;
    public void setHelper(AnimalHelper helper) {
        this.helper = helper;
    }
    public void handle( ){
        //...
        helper.help( );
        //...
    }
}
package principle_dip2;
public class TigerHelper implements AnimalHelper{
    public void help( ){
        //......
    }
}

依赖注入模式(Dependency Injection):在运行时将类的依赖注入到代码中。通过将依赖定义为接口,并将实现这个接口的实体类注入到主类的构造器中来实现这个模式。这允许程序员在不同的实现之间转换而不用去修改主类。依赖注入模式可以通过单一责任原则(Single Responsibility Principle)SRP来使得代码高内聚(high cohesion),因为所依赖的通常都是完成独立的功能的对象,例如,(通过DAO进行)数据存取或(通过Service和Delegate类实现)业务服务。

控制反转容器(Inversion of Control Container,IoC),是一个支持依赖注入的容器。这种方式下,可以采用一个中心容器,例如Spring框架,Guice或者HiveMind,来定义哪个依赖应该使用哪个实体类。Ioc的松耦合性可以带来更多的灵活性,并且在程序运行时更容易去切换到正确的依赖对象上。控制反转模式的基本概念是,不去实际生成对象,而是去定义如何生成对象。不用直接在代码中将模块和服务硬编码在一起,而是在配置文件中描述哪个模块需要哪个服务。容器(例如Spring框架这个IoC容器)会负责将这两者绑定起来。应用IoC的时候,某对象所需的依赖会在创建的时候通过外部实体传入,这些外部实体用来协调系统中的不同对象。也就是说,依赖是被注入到对象中去的。因此,IoC就是关于一个对象如何获得其协作对象的引用的一种责任反转机制。

DI和IoC的真正强大之处在于,在运行时而非编译时绑定类间关系。例如,在Seam框架中,你可以对一个接口进行两种实现:真正的实现和模拟(mock)的实现,而在运行时根据某个属性、另一个文件存在与否或者某个优先值去决定真正调用哪一个实现。这尤其当你希望程序在不同场景下表现不同的行为时,这是非常好用的。DI和IoC的另外一个好处是,使得代码更容易进行单元测试。当然也有其他一些好处,例如,不用使用工厂或者单例模式就可以实现松耦合,其实现方法一致因此适合缺乏经验的程序员,等等。当然,享受这些好处是要付出代价的,例如系统复杂性会随之增加,另外在使用时也需要更加小心,不能因为这个技术受欢迎就滥用,而是在能够真正体现其优势的地方才去使用。

注意:上下文依赖注入(Contexts and Dependency Injection)是用来描述标准依赖注入的一个尝试。CDI是Java EE 6 stack的一部分,也就是说任何一个运行在Java EE 6兼容容器之上的应用都可以轻松使用CDI。Weld就是CDI的一个可参考的实现。
  • 大小: 18.8 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics