简介
IOC( Inversion of Control ), 控制反转, 用来减低代码之间的耦合度.
IOC常见的注入形式有三种: 构造函数注入, set方法注入, 接口注入. 由于一般都是通过构造函数注入接口的实现, 因此也叫依赖注入.
解析现在有一个场景, 在学校, 小明是一个班长, 现在要去收作业. 我定义了一个学校类, 学校类定义了收集所有人作业的方法, 小明类定义了收集每个人作业的方法. 具体怎么实现的我们不管, 今天的重点不是这个. 可以看到, XiaoMing类 和 School类 是一种高耦合的状态, 谁也离不开谁, 这在写代码中是不行的.
public class School {
// 收集所有人的作业public void Homework() {
// 创建一个小明对象XiaoMing xiaoMing = new XiaoMing();
// 让小明执行收作业的方法xiaoMing.Collect();
}
}
public class XiaoMing {
// 收作业的方法public void Collect() {
}
}
我们再新建一个 Monitor班长接口 , 让 XiaoMing类 实现这个接口, 这样, 在一定程度上减少了 School类 对 XiaoMing类 的耦合程度. 但还是存在依赖关系. 可以看到, School类 还是比较依赖XiaoMing类.
public interface Monitor {
public void Collect();
}
public class XiaoMing implements Monitor {
// 收作业的方法public void Collect() {
}
}
public class School {
// 收集所有人的作业public void Homework() {
// 创建一个小明对象Monitor monitor = new XiaoMing();
// 让小明执行收作业的方法monitor.Collect();
}
}
现在我们再来引入一个教师类. 由教师类引入实例化XiaoMing类, 并实例化School类. 这样, XiaoMing类的控制权就从School类转交到了Teacher类中, 这就是所谓的控制反转.
具体的实现与三种方式. 下面我们来看三种实现方式
实现之一 --- 构造函数注入通过构造函数注入, 一般是定义一个接口, 在调用类时, 将接口的实现类通过构造函数注入. 在本例中, 我们定义了Monitor接口, 在调用School类时通过构造函数注入Monitor的实现类 --- XiaoMing.
School类不必关心到底是谁是班长就行了, 只要能调用Collect方法就行了.
public class School {
private Monitor monitor;
// 注入Monitor的实现类public School(Monitor monitor) {
this.monitor = monitor;
}
// 收集所有人的作业public void Homework() {
// 让小明执行收作业的方法monitor.Collect();
}
}在实例化School类时, 将XiaoMing注入. Monitor的实现类是什么, 由Teacher类来控制, 在此之前, Monitor的实现类是由School类控制的.
public class Teacher {
public static void main(String[] args) {
Monitor monitor = new XiaoMing();// 此处是关键, 注意School school = new School(monitor);// 注入Monitor的实现类school.Homework();
}
}
实现之二 --- set方法注入我们看上面的例子, 当我们实例化School类的时候, Monitor类的实现类就已经注入了. 但有个时候, 学校类可能要调用其他Monitor的实现类. 比如说XiaoHong也是Monitor的实现类, School类先要调用XiaoHong的方法, 再调用XiaoMing的方法, 这个时候, 通过构造函数注入就已经不合适了, 所以我们通过set方法注入.
public class School {
private Monitor monitor;
// 此处是关键, 注意public void setMonitor(Monitor monitor) {
this.monitor = monitor;
}
// 收集所有人的作业public void Homework() {
// 让小明执行收作业的方法monitor.Collect();
}
}在合适的时候注入合适的接口实现类.
public class Teacher {
public static void main(String[] args) {
Monitor monitor = new XiaoMing();
School school = new School();
school.setMonitor(monitor);// 在合适的时候注入XiaoMing类school.Homework();
Monitor monitor2 = new XiaoHong();
school.setMonitor(monitor2);// 在合适的时候注入XiaoHong类school.Homework();
}
}
实现之三 --- 接口注入第三种方法, 通过接口注入. 把Monitor类再抽象成一个接口, 让School类实现Monitor的接口. 这种方法过于复杂, 且和构造函数注入并无太大区别, 不推荐使用.
public interface IMonitor {
public void iMonitor(Monitor monitor);
}
public class School implements IMonitor {
private Monitor monitor;
@Override
public void iMonitor(Monitor monitor) {
this.monitor = monitor;
}
// 收集所有人的作业public void Homework() {
// 让小明执行收作业的方法monitor.Collect();
}
}
public class Teacher {
public static void main(String[] args) {
Monitor monitor = new XiaoMing();
School school = new School();
school.iMonitor(monitor);
school.Homework();
}
}
参考: