我们为什么会需要用到依赖注入

依赖注入是面向对象编程的一种设计模式,目的就是为了降低耦合。

举个例子:就好比 IOC 和 AOP 有什么关系,IOC 主要是解耦和方便附加功能(用AOP实现)。

思想上就是

上帝说,要有光,于是就有了光,谁给的光,造光的神啊,你只需要知道你要什么,你不需要知道怎么来的(比如:接口)。

再简单的例子:你是个富二代,你什么都不用操心,需要什么,开口就行,你的富爸爸(IOC 容器)会帮你搞定。
再简单举个例子:你在钓鱼,鱼就是接口 Fish,你的钓竿给了你鱼,可能是鲤鱼,也有可能是鲨鱼,这些鱼就是 Fish 的具体实现,而你不需要知道是什么鱼,只需要知道是鱼就行。

接下来上码吧,也许还是码能快速理解

以 Java 语言为例子,我们在码 code 的时候往往会用到别的类来实现一些功能,就像:

1
2
3
4
5
6
7
8
9
10
11
12
public class ClassA {

private ClassB classB;

public ClassA() {
this.classB = new ClassB();
}

public void do() {
classB.action();
}
}

这个时候就产生了耦合, ClassA 依赖于 ClassB,ClassA 必须借助 ClassB 来完成一些功能,然而我们再 ClassA 直接创建了 ClassB 的实例,产生了耦合性,违背了单一职责原则,ClassB 的实例不应由 ClassA 来完成,耦合偶上了,藕断丝连的,扩展性也会差很多,如果我们的 ClassB 在某一段时间之后加了成员变量,那么 ClassA 也就不得不改动构造方法了,这样就不符合开闭原则。 ps: 有多少小伙伴干了这事,自己默默地举起小爪子。

因此我们需要一种注入方式,将依赖注入到宿主类中,如:
通过set方法:
1
2
3
4
5
6
7
8
public class ClassA {

private ClassB classB;

public void setClassB(ClassB classB) {
this.classB = classB;
}
}
Interface :
1
2
3
4
5
6
7
8
9
10
11
12
public interface ClassBInterface {
void setClassB(ClassB classB);
}

public class CLassA implements ClassBInterface {

private ClassB classB;

void setClassB(ClassB classB) {
this.classB = classB;
}
}
构造函数注入(Contructor Injection)
1
2
3
4
5
6
7
8
public class ClassA {

private ClassB classB;

public ClassA(ClassB classb) {
this.classB = classB;
}
}
亦或者通过注解
1
2
3
public class ClassA {
@Inject private ClassB classB;
}

依赖注入降低了依赖和被依赖类型间的耦合,在修改被依赖的类型实现时,不需要修改依赖类型的实现,同时,对于依赖类型的测试,可以更方便的使用 Mocking Object 替代原有的被依赖类型,以达到对依赖对象独立进行单元测试的目的。

最后需要注意的是,依赖注入只是控制反转的一种实现方式。控制反转还有一种常见的实现方式称为依赖查找。

— END