控制反转、依赖注入和策略模式在Java中的示例。

7
我经常混淆这三个术语,它们对我来说非常相似。有人能否用例子清楚地向我解释它们。我看过类似的帖子,但仍不完全明白。
3个回答

20
依赖注入是一种模式,它告诉一个类它的依赖关系将是什么,而不是要求这个类知道如何找到所有的依赖关系。

例如,你可以从以下内容开始:

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(...);
   }
}

这将减少代码中的耦合,特别是当您想对进行单元测试时非常有用。现在,您可以将传递到测试数据库中,而不是总是针对<10.167.1.25>上找到的数据库运行。或者,在快速测试中更有用的是,您可以传递一个的实现或子类,它甚至不连接到数据库,只是丢弃请求!
然而,这种基本的依赖注入使得“连线”(为对象提供其依赖项)更加困难,因为您已经用通过整个对象图传递依赖项替换了使用全局变量(或本地实例化对象)访问依赖项。
请看一个例子,其中UserFetcherAccountManager的依赖项,而AccountManagerAdminConsole的依赖项。然后,AdminConsole需要将DbConnection实例传递给AccountManager,而AccountManager需要将其传递给UserFetcher......即使AdminConsoleAccountManager都不需要直接使用DbConnection

控制反转容器(Spring、Guice等)旨在通过自动连接(提供)依赖项来使依赖注入更加简单。为此,您只需告诉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"));
    }
}

现在,当使用Guice或Spring构造UserFetcher时,DbConnection会自动提供。
Guice在依赖注入背后的动机以及进一步使用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;
}

我在多本技术文献中寻找这个解释,但从未找到像这样教学性和完整的内容。恭喜! - deldev

2
控制反转意味着运行时框架将所有组件连接在一起(例如Spring)。依赖注入是IoC的一种形式(我不知道是否存在另一种形式的IoC)(参见:http://en.wikipedia.org/wiki/Inversion_of_control)。
策略模式是一种设计模式(由GoF定义),其中算法可以被另一个算法替换(参见:http://en.wikipedia.org/wiki/Strategy_pattern)。这通过提供同一接口的几个实现来实现。当使用像Spring这样的IoC时,如果您有多个接口的实现,并且如果您可以通过配置从一个实现切换到另一个实现,则正在使用策略模式。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接