我经常对这三个术语感到困惑。这三个看起来与我相似。有人可以通过示例清楚地向我解释。
我看过类似的帖子,完全不明白。
答案 0 :(得分: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(...);
}
}
这减少了代码中的耦合,如果您想要单元测试UserFetcher
,这尤其有用。现在,您可以将UserFetcher
传递到测试数据库,而不是10.167.1.25
始终对DbConnection
处找到的数据库运行。或者,在快速测试中更有用,您可以传入DbConnection
的实现或子类,它甚至连接到数据库,它只是丢弃请求!
然而,这种原始依赖注入使连接(提供具有依赖性的对象)更加困难,因为您已经使用全局变量(或本地实例化)替换了访问依赖性通过整个对象图传递依赖关系。
考虑UserFetcher
是AccountManager
的依赖关系的情况,AdminConsole
是AdminConsole
的依赖关系。然后DbConnection
需要将AccountManager
个实例传递给AccountManager
,而UserFetcher
需要将其传递给AdminConsole
... ,即使它们都不是{{} 1}}或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有a really good Wiki article关于依赖注入的动机,并进一步使用IoC容器。它一直值得一读。
策略模式只是依赖注入的一个特例,您可以在其中注入 logic 而不是对象(即使在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;
}
答案 1 :(得分:2)
控制反转意味着运行时框架将所有组件连接在一起(例如Spring)。依赖注入是IoC的一种形式(我不知道是否存在其他形式的IoC)(参见:http://en.wikipedia.org/wiki/Inversion_of_control)。
策略模式是一种设计模式(由GoF定义),其中算法可以被另一个替换(参见:http://en.wikipedia.org/wiki/Strategy_pattern)。这是通过提供相同接口的几个实现来存档的。当使用像Spring这样的IoC时,如果你有多个接口实现,并且你可以通过配置从一个实现切换到另一个实现,那么你就是在使用策略模式。
答案 2 :(得分:0)
我还建议阅读Spring文档的介绍章节,该章节重点讨论这个问题: Introduction to Spring Framework
前几段应该这样做。
这也链接到:Inversion of Control Containers and the Dependency Injection pattern
这也提供了对这些非常重要的核心概念的激励观点。