假如有以下java代码
class MovieLister...
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
可以看到,类 MovieLister 的一个方法 moviesDirectedBy 使用了另外一个对象的方法 finder.findAll();
学过设计模式的都知道,应该面向接口,而不应该面向具体实现 编程 (如果这个不理解,推荐去看一下 head first 的设计模式一书), 所以以上代码应该优化为:
public interface MovieFinder {
List findAll();
}
class MovieLister...
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
这样, MovieLister就不再唯一依赖于某个具体的finder对象了,而是所有实现在MovieFinder接口的对象都可以使MovieLister中的 moviewsDirectBy方法工作正常
不过,有一点是不可避免的,就是movieLister要在某一时刻决定使用哪一个“具体”的 实现了movieFinder接口的 类对象。
依赖关系见下图所示Figure 1:
class MovieLister...
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
可以看到,类 MovieLister 的一个方法 moviesDirectedBy 使用了另外一个对象的方法 finder.findAll();
学过设计模式的都知道,应该面向接口,而不应该面向具体实现 编程 (如果这个不理解,推荐去看一下 head first 的设计模式一书), 所以以上代码应该优化为:
public interface MovieFinder {
List findAll();
}
class MovieLister...
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
这样, MovieLister就不再唯一依赖于某个具体的finder对象了,而是所有实现在MovieFinder接口的对象都可以使MovieLister中的 moviewsDirectBy方法工作正常
不过,有一点是不可避免的,就是movieLister要在某一时刻决定使用哪一个“具体”的 实现了movieFinder接口的 类对象。
依赖关系见下图所示Figure 1:
从图上可以看出, MovieLister类,不仅依赖于接口, 也依赖于接口的某一个具体实现。
那能不能彻底摆脱对某一实现的依赖,做到纯纯的, 只依赖于 MoveiFinder 接口呢?!
如果可以,那我们什么时候,以及如果去生成一个具体的实现去跟 MovieLister合作呢?
这看似是一个不可能完成的任务啊?
当,当, 当, 答案就是用 Inversion of Control
什么是控制反转, 啥叫控制,又是如何反转的?
假如A类的方法method_a() 需要使用B类的方法method_b()。 那么在a()函数的某一行,一定会生成一个B的对象b, 然后调用 b.method_b().
这种情况是再正常不过的了, 在这种觉常见的情况下, A类就具有控制权,它有权决定,初始化哪个类,并调用相应的哪个方法。
那又是如何反转的呢?
答案是使用一个额外的装载器(assembler) ,它会在适应的时机,给A注入需要的B
这样,控制权就不再属于A 的,而是属于装载器了,就实现在控制反转。
也正是应该装载器会在正确的时机 把A “注入“给 B ,所以 控制反转又被冠以 依赖注入的名称
依赖注入的关系图如 Figure-2
依赖注入的三种方式
Ioc1 (Interface injection) 接口注入
Ioc2 (Setter injection) Setter注入
Ioc3 (constructor injection) 构造函数注入
好了,概念就介绍到这里了, 如果还是不懂或者有更深厚的兴趣,请参考原文继续阅读
详情参见 原文地址:http://martinfowler.com/articles/injection.html#InversionOfControl