用Java中的例子反转控制,依赖注入和策略模式

Jav*_*a P 7 java spring dependency-injection inversion-of-control strategy-pattern

我经常对这三个术语感到困惑.这三个看起来与我相似.有人可以通过示例清楚地向我解释.

我看过类似的帖子,完全不明白.

Mar*_*ers 20

依赖注入是指告诉类其依赖性是什么的模式,而不是要求类知道在哪里找到它的所有依赖项.

所以,例如,你从这里开始:

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

   public List<User> getUsers() {
      return conn.fetch(...);
   }
}
Run Code Online (Sandbox Code Playgroud)

这样的事情:

public class UserFetcher {
   private final DbConnection conn;

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

   public List<User> getUsers() {
      return conn.fetch(...);
   }
}
Run Code Online (Sandbox Code Playgroud)

这减少了代码中的耦合,如果您想进行单元测试,这尤其有用UserFetcher.现在,您可以将a 传递给测试数据库,而不是UserFetcher 始终针对找到的数据库运行.或者,更在快速测试非常有用,可以实现或子类通过甚至不连接到一个数据库,它只是丢弃的请求!10.167.1.25DbConnectionDbConnection

但是,这种原始依赖注入使得布线(提供具有其依赖性的对象)更加困难,因为您已经使用全局变量(或本地实例化对象)替换了访问依赖性,并通过整个对象图传递依赖性.

想想UserFetcher一个依赖的情况AccountManager,它是一个依赖AdminConsole.然后AdminConsole需要传递DbConnection实例AccountManager,并AccountManager需要将其传递给UserFetcher... 即使既不需要AdminConsole也不AccountManager需要DbConnection直接使用!

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

因此,如果我们使用构造函数注入,我们的最后一个示例可能与Guice一样:

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(...);
   }
}
Run Code Online (Sandbox Code Playgroud)

我们必须配置IoC容器.在Guice,这是通过实施Module; 在Spring中,您通常通过XML 配置应用程序上下文.

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

现在,当UserFetcher由Guice或Spring构建时,DbConnection会自动提供.

Guice有一篇关于依赖注入背后动机的非常好的Wiki文章,并进一步使用了IoC容器.它一直值得一读.

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

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

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

但是,如果您想将此代码扩展到新的司法管辖区,并使用不同的销售税计划呢?您可以注入计算税的逻辑,如下所示:

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;
}
Run Code Online (Sandbox Code Playgroud)