回答

18

依赖注入指的是告诉类的依赖关系是什么样的模式,而不是要求类知道在哪里找到它的所有依赖关系。

因此,举例来说,你从这个去:

public class UserFetcher { 
    private final DbConnection conn = 
     new DbConnection("10.167.1.25", "username", "password"); 

    public List<User> getUsers() { 
     return conn.fetch(...); 
    } 
} 

到这样的事情:

public class UserFetcher { 
    private final DbConnection conn; 

    public UserFetcher(DbConnection conn) { 
     this.conn = conn; 
    } 

    public List<User> getUsers() { 
     return conn.fetch(...); 
    } 
} 

这降低耦合的代码,这是非常有用的,如果你想进行单元测试UserFetcher。现在,您可以将DbConnection传递给测试数据库,而不是运行10.167.1.25的数据库,而不是UserFetcher总是。或者,在快速测试中更加有用,您可以传入一个DbConnection的实现或子类,它甚至不连接到数据库,它只是丢弃请求!

但是,这种原始依赖注入使得布线(提供与它的依赖的对象)更加困难,因为你已经替换为使依赖访问使用全局变量(本地实例化的对象或)的依赖性围绕整个对象图。

想象一下UserFetcherAccountManager的依赖关系,其依赖于AdminConsole。然后AdminConsole需要的DbConnection实例传递给AccountManager,并AccountManager需要将它传递给UserFetcher ... 即使没有AdminConsole也不AccountManager需要直接使用DbConnection

控制容器的反转(春,吉斯等)的目的是通过自动布线(提供)的依赖关系,使依赖注入容易。要做到这一点,你告诉你的IoC容器一次如何提供一个对象(在Spring中,这称为bean),并且每当另一个对象请求该依赖关系时,它将由容器提供。

所以我们的最后一个例子可能看起来像这样与吉斯,如果我们使用构造器注入:

public class UserFetcher { 
    private final DbConnection conn; 

    @Inject //or @Autowired for Spring 
    public UserFetcher(DbConnection conn) { 
     this.conn = conn; 
    } 

    public List<User> getUsers() { 
     return conn.fetch(...); 
    } 
} 

我们必须要配置的IoC容器。在Guice中,这是通过执行Module完成的;在Spring中,通常通过XML配置应用程序上下文

public class MyGuiceModule extends AbstractModule {  
    @Override 
    public void configure() { 
     bind(DbConnection.class).toInstance(
      new DbConnection("localhost", "username", "password")); 
    } 
} 

现在,当UserFetcher由吉斯或Spring构造时,DbConnection被自动提供。

Guice有a really good Wiki article关于依赖注入背后的动机,并进一步使用IoC容器。这是值得一读的。

策略模式是依赖注入,在那里你注入逻辑而不是一个对象(即使在Java中,逻辑将在对象封装)的一个特例。这是一种解耦独立业务逻辑的方式。

例如,你可能有这样的代码:

public Currency computeTotal(List<Product> products) { 
    Currency beforeTax = computeBeforeTax(products); 
    Currency afterTax = beforeTax.times(1.10); 
} 

但是,如果你想这个代码扩展到一个新的司法管辖区,以不同的销售税方案?您可以注入计算税的逻辑,如下所示:

public interface TaxScheme { 
    public Currency applyTax(Currency beforeTax); 
} 

public class TenPercentTax implements TaxScheme { 
    public Currency applyTax(Currency beforeTax) { 
     return beforeTax.times(1.10); 
    } 
} 

public Currency computeTotal(List<Product> products, TaxScheme taxScheme) { 
    Currency beforeTax = computeBeforeTax(products); 
    Currency afterTax = taxScheme.applyTax(beforeTax); 
    return afterTax; 
} 
2

控制反转意味着运行时框架将所有组件连接在一起(例如Spring)。依赖注入是IoC的一种形式(我不知道是否存在另一种形式的IoC)(请参见:http://en.wikipedia.org/wiki/Inversion_of_control)。

策略模式是一种设计模式(由GoF定义),其中算法可以被另一个替换(参见:http://en.wikipedia.org/wiki/Strategy_pattern)。这是通过提供几个相同接口的实现来存档的。当使用类似Spring的IoC时,如果您有多个接口实现,并且您可以通过配置从实现切换到另一个实现,那么您正在使用策略模式。