Inversion of Control (控制倒置)

Paul Hammant

翻译:James Shen

 

摘要

Inversion of Control (逆向控制) 是一种用来解决模块(实际上也可以是简单的Java类)之间依赖关系、配置及生命周期的设计模式,其中对模块依赖关系的处理是Ioc的精华部分。

模块依赖

模块之间降低耦合度有以下好处:

  • 增加类的复用程度

  • 使类的测试更加容易

  • 使整个系统更容易组装和配置

 

说明

运用了Ioc模式后我们不需求再自己管理模块之间的依赖关系,只需要声明这中依赖关系由容器去实现这种依赖关系。就好像把对模块之间依赖关系的控制进行了倒置,不再由模块自己来建立这种依赖关系而交给容器(例如PicoContainerSpring)去管理。

范例

下面是一个非常简单的例子来说明Ioc模式:

public interface Orange { 

  // methods

}

 

public class AppleImpl implements Apple { 

  private Orange orange; 

  public AppleImpl(Orange orange) {    

    this.orange = orange; 

  }

  // other methods

}

 

public class AppleImpl implements Apple{ 

  private Orange orange; 

  public Apple() {

    this.orange = new OrangeImpl();

  } 

  // other methods

}

 

public class AppleImpl implements Apple {

  private static Orange orange = OrangeFactory.getOrange();

  public Apple() {

  } 

  // other methods

}

这里的问题在于:你依赖OrangleImpl来具体实现orange接口,这样apple类就缺乏足够的灵活性。这些代码都是硬写的,不能被复用更不能通过一个classloader来生成不同的实例。

 

模块的配置

有时我们的配置如下:

public class BigFatComponent { 

  String config01; 

  String config02; 

  public BigFatComponent() {   

    ResourceFactory resources = new ResourceFactory(new File("mycomp.properties"));   

    config01 = resources.get("config01");   

    config02 = resources.get("config02"); 

  } 

  // other methods

}

 使用了Ioc模式可以优化如下:

public class BigFatComponent { 

  String config01; 

  String config02; 

  public BigFatComponent(String config01, String config02) {   

    this.config01 = config01;   

    this.config02 = config02; 

  } 

  // other methods

}

 

public interface BigFatComponentConfig { 

  String getConfig01();

  String getConfig02();

}

public class BigFatComponent { 

  String config01; 

  String config02; 

  public BigFatComponent(BigFatComponentConfig config) {   

    this.config01 = config.getConfig01();   

    this.config02 = config.getConfig02(); 

  } 

  // other methods

}

这样我们可以灵活的对BigFatComponentConfig有不同的实现:

  1. 直接写代码来设置配置

  2. XML文件读取配置

  3. Properties文件读取配置

 

根据需要我们可以选择不同的实现

 

模块的生命周期

模块的生命周期一般从构造函数就开始了。Ioc模式建议我们实现Startable接口通过start/stop方法来开始和结束模块,这样方便容器来控制模块的生命周期。

public class SomeDaemonComponent implements Startable { 

  public void start() {

    // listen or whatever 

  } 

  public void stop() {

  }

  // other methods

}



例外情况

日志对于Ioc来说是一种例外情况,Apache下的Commons-LoggingLog4J都不支持Ioc模式。他们典型的用法是在应用程序中静态的直接调用,PicoContainer不建议我们对日志模块进行复用。

 

你可能感兴趣的:(java,methods,string,ioc,apple,class,classloader)