Paul Hammant
翻译:James Shen
摘要
Inversion of Control (逆向控制) 是一种用来解决模块(实际上也可以是简单的Java类)之间依赖关系、配置及生命周期的设计模式,其中对模块依赖关系的处理是Ioc的精华部分。
模块依赖
模块之间降低耦合度有以下好处:
- 增加类的复用程度
- 使类的测试更加容易
- 使整个系统更容易组装和配置
说明
运用了Ioc模式后我们不需求再自己管理模块之间的依赖关系,只需要声明这中依赖关系由容器去实现这种依赖关系。就好像把对模块之间依赖关系的控制进行了倒置,不再由模块自己来建立这种依赖关系而交给容器(例如PicoContainer、Spring)去管理。
范例
下面是一个非常简单的例子来说明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有不同的实现:
- 直接写代码来设置配置
- 从XML文件读取配置
- 从Properties文件读取配置
根据需要我们可以选择不同的实现
模块的生命周期
模块的生命周期一般从构造函数就开始了。Ioc模式建议我们实现Startable接口通过start/stop方法来开始和结束模块,这样方便容器来控制模块的生命周期。
public class SomeDaemonComponent implements Startable { public void start() { // listen or whatever } public void stop() { } // other methods } |
例外情况
日志对于Ioc来说是一种例外情况,Apache下的Commons-Logging和Log4J都不支持Ioc模式。他们典型的用法是在应用程序中静态的直接调用,PicoContainer不建议我们对日志模块进行复用。