我经常对这三个术语感到困惑。这三个和我很像。有人可以用例子清楚地向我解释。
我看过类似的帖子,完全不明白。
我经常对这三个术语感到困惑。这三个和我很像。有人可以用例子清楚地向我解释。
我看过类似的帖子,完全不明白。
依赖注入是指告诉一个类它的依赖关系是什么的模式,而不是要求类知道在哪里可以找到它的所有依赖关系。
所以,例如,你从这个开始:
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
。现在,您可以将 a 传递给测试数据库,而不是UserFetcher
总是针对在 找到的数据库运行。或者,在快速测试中更有用的是,您可以传入一个甚至不连接到数据库的实现或子类,它只是丢弃请求!10.167.1.25
DbConnection
DbConnection
然而,这种原始的依赖注入使得连接(为对象提供其依赖项)变得更加困难,因为您已经将使用全局变量(或本地实例化的对象)访问依赖项替换为通过整个对象图传递依赖项.
考虑一个情况,其中UserFetcher
是 的依赖项AccountManager
,这是 的依赖项AdminConsole
。然后AdminConsole
需要将DbConnection
实例传递给AccountManager
,并且AccountManager
需要将其传递给UserFetcher
...即使既不需要AdminConsole
也不AccountManager
需要DbConnection
直接使用!
控制容器(Spring、Guice 等)的反转旨在通过自动连接(提供)依赖项来简化依赖项注入。要做到这一点,你告诉你的 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(...);
}
}
我们必须配置 IoC 容器。在 Guice 中,这是通过实现Module
; 在 Spring中,您通常通过 XML配置应用程序上下文。
public class MyGuiceModule extends AbstractModule {
@Override
public void configure() {
bind(DbConnection.class).toInstance(
new DbConnection("localhost", "username", "password"));
}
}
现在当UserFetcher
由 Guice 或 Spring 构建时,DbConnection
会自动提供。
Guice 有一篇关于依赖注入背后的动机以及进一步使用 IoC 容器的非常好的 Wiki 文章。值得通读一遍。
策略模式只是依赖注入的一个特例,你注入的是逻辑而不是一个对象(即使在 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;
}
控制反转意味着运行时框架将所有组件连接在一起(例如 Spring)。依赖注入是 IoC 的一种形式(我不知道是否存在另一种形式的 IoC)(参见:http ://en.wikipedia.org/wiki/Inversion_of_control )。
策略模式是一种设计模式(由 GoF 定义),其中算法可以被另一个算法替换(参见:http ://en.wikipedia.org/wiki/Strategy_pattern )。这是通过提供相同接口的多个实现来存档的。在使用像 Spring 这样的 IoC 时,如果您有多个接口实现,并且可以通过配置从一个实现切换到另一个实现,那么您正在使用策略模式。
我也推荐阅读 Spring 文档的介绍章节,主要关注这个问题:Introduction to Spring Framework
前几段应该做的。
这也链接到:控制容器的反转和依赖注入模式
这也提供了这些非常重要的核心概念的动机视图。