【发布时间】:2012-09-14 11:50:36
【问题描述】:
我经常对这三个术语感到困惑。这三个和我很像。有人可以用例子向我解释清楚吗?
看过类似的帖子,没完全看懂。
【问题讨论】:
标签: java spring dependency-injection inversion-of-control strategy-pattern
我经常对这三个术语感到困惑。这三个和我很像。有人可以用例子向我解释清楚吗?
看过类似的帖子,没完全看懂。
【问题讨论】:
标签: java spring dependency-injection inversion-of-control strategy-pattern
依赖注入指的是告诉一个类它的依赖将是什么的模式,而不是要求类知道在哪里可以找到它的所有依赖。
所以,例如,你从这个开始:
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 传递给测试数据库,而不是UserFetcher 总是 运行在10.167.1.25 上的数据库。或者,在快速测试中更有用的是,您可以传入 DbConnection 的实现或子类,它甚至不连接到数据库,它只是丢弃请求!
然而,这种原始的依赖注入使得 wiring(为对象提供其依赖项)变得更加困难,因为您已经替换了使用全局变量(或本地实例化的对象)访问依赖项通过整个对象图传递依赖关系。
想想UserFetcher 是AccountManager 的依赖关系的情况,它是AdminConsole 的依赖关系。那么AdminConsole 需要将DbConnection 实例传递给AccountManager,而AccountManager 需要将它传递给UserFetcher...即使AdminConsole 和AccountManager 都不需要使用@ 987654339@直接!
控制反转容器(Spring、Guice 等)旨在通过自动连接(提供)依赖项使依赖项注入更容易。为此,您告诉您的 IoC 容器 once 如何提供一个对象(在 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 有 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;
}
【讨论】:
我也推荐阅读 Spring 文档的介绍章节,主要关注这个问题: Introduction to Spring Framework
前几段应该做。
这也链接到:Inversion of Control Containers and the Dependency Injection pattern
这也提供了对这些非常重要的核心概念的启发性观点。
【讨论】:
控制反转意味着运行时框架将所有组件连接在一起(例如 Spring)。依赖注入是 IoC 的一种形式(我不知道是否存在另一种形式的 IoC)(参见:http://en.wikipedia.org/wiki/Inversion_of_control)。
策略模式是一种设计模式(由 GoF 定义),其中算法可以被另一个算法替换(参见:http://en.wikipedia.org/wiki/Strategy_pattern)。这是通过提供相同接口的多个实现来存档的。在使用像 Spring 这样的 IoC 时,如果一个接口有多个实现,并且可以通过配置从一个实现切换到另一个实现,那么您就是在使用策略模式。
【讨论】: