控制反转和依赖注入到底是什么?
从案例中引入
先看一个书上的案例
简化一下,就是A这个类需要使用到B这个类的performAction()
方法,那么很简单:
public class A{
private B b;
public void method(){
B b= new B();
b.performAction();
}
}
这样做存在的问题:A和B直接耦合,于是我们把 B 改成 B需要实现的接口 :
public class A{
private BInterface b;
public void method(){
b = new B();
b.performAction();
}
}
但是这样做还是得在A类中实现BInterface这个接口b = new B()
也就是说,我们的最终目的,是把B
的具体实现从 A
中剥离,只要知道 A
里面有个 B
就好了。
于是我们引入第三方作为协调者:另一个类 C
,由C
来负责A
中BInterface
的具体实现,这样,在A
中只要保留一个BInterface
就可以了。也就是说,B的实例化的控制权由A
转移到了C
,亦即 控制反转(Inverse of Control,IoC) ,或称依赖注入(Dependency Inject , DI) 两个是同一思想,只是表达方式有所区别。
控制反转和依赖注入的定义
- 控制反转:某一接口的具体实现类(
B
)的控制权从调用类(A
)中移除,转交给第三方(C
)决定。 - 依赖注入:让调用类(
A
)对某一接口实现类(B
)的依赖关系由第三方(容器或协作类)注入,以移除调用类(A
)对某一接口实现类(B
)的依赖。
控制反转或依赖注入的实现方法
- 构造函数注入
- 属性注入
- 接口注入
//构造函数注入
public A {
private BInterface b;
public A(BInterface b){
this.b = b;
}
public void method(){
b.performAction();
}
}
//属性注入
public class C{
public void coordinate(){
BInterface b = new B();
A = new A(b);
}
}
//接口注入 接口注入需要将所有依赖注入的方法提取到一个接口中,调用类`A` 通过实现该接口提供相应的注入方法,
//因此,我们需要先声明一个接口 `Arrangable` 。
public class A implements Arrangable{
private BInterface b;
public void injectBInterface(BInterface b){
this.b = b;
}
}
public C{
public void coordinate(){
BInterface b = new B();
A a = new A();
a.inject(b);
}
}
//接口注入是不被提倡的,因为它烦
通过上述三种方法,虽然 A
和B
解耦了 ,A
无需关注 B
的实例化工作,但是这些工作的代码量依然存在,只是转移到了C
而已。
怎么办呢? 解决方法:使用 spring 和 spring boot 框架。