概念
控制反转(Inversion of Control,简称IOC)是一个概念,是一种思想,其核心是将对象的创建、依赖管理等控制权从代码内部转移到外部容器或框架,以此降低代码间的耦合度,提高系统的灵活性和可维护性。
下面用制造汽车需要引擎、轮胎等零件的场景解释含义
- 假设现在要生产汽车、货车、客车、出租车,它们都是使用【1代引擎】
代码如下:
1代引擎
public class EngineV1 {
private String name = "1代引擎";
public String getName() {
return name;
}
}
汽车
public class Car {
private String name = "汽车";
private EngineV1 engineV1;
public Car(EngineV1 engineV1) {
this.engineV1 = engineV1;
}
public void info() {
System.out.println(name + "使用的是" + engineV1.getName());
}
}
货车
public class Van {
private String name = "货车";
private EngineV1 engineV1;
public Van (EngineV1 engineV1) {
this.engineV1 = engineV1;
}
public void info () {
System.out.println(name + "使用的是" + engineV1.getName());
}
}
测试
public class Test1 {
public static void main(String[] args) {
Car car = new Car(new EngineV1());
car.info();
Van van = new Van(new EngineV1());
van.info();
}
}
假设上述汽车和货车,都依赖于【1代引擎】才能启动,没有【1代引擎】汽车和货车就启动不了。假如我们还有很多其他类型的车都是依赖于【1代引擎】,有一天我想把所有的【1代引擎】换成 【2代引擎】我该怎么做?
全局搜索【1代引擎】修改为 【2代引擎】,想想都有点麻烦。
- 我们换一种思路来实现,解决上述问题
代码如下:
引擎接口
public interface IEngine {
String getName();
}
1代引擎
public class EngineV1 implements IEngine {
private String name = "1代引擎";
@Override
public String getName() {
return name;
}
}
2代引擎
public class EngineV2 implements IEngine{
private String name = "2代引擎";
public String getName() {
return name;
}
}
汽车
public class Car {
private String name = "汽车";
// 现在不依赖于具体哪个引擎,直接对接引擎接口
private IEngine engine;
public Car (IEngine engine) {
this.engine = engine;
}
public void info() {
System.out.println(name + "使用的是" + engine.getName());
}
}
货车
public class Van {
private String name ="货车";
// 现在不依赖于具体哪个引擎,直接对接引擎接口
private IEngine engine;
public Van (IEngine engine) {
this.engine = engine;
}
public void info() {
System.out.println(name + "使用的是" + engine.getName());
}
}
测试
public class Test2 {
public static void main(String[] args) {
// Car car = new Car(new EngineV1());
// car.info();
//
// Van van = new Van(new EngineV1());
// van.info();
Car car = new Car(new EngineV2());
car.info();
Van van = new Van(new EngineV2());
van.info();
}
}
上述代码中,小汽车和货车不再依赖具体的某代引擎,而是依赖于引擎接口,进行了反转。现在生产汽车的时候,给汽车什么引擎它就用什么引擎,汽车就脱离了只能用【1代引擎】绝对绑定形式了。这是依赖倒转(DIP)的一种表现形式。
这时如果我们需要把【2代引擎】换成【3代引擎】,只需要在创建汽车的时候给他【3代引擎】就能实现。
上述代码我们还能进行优化,现在的引擎都是我们在创建汽车和货车时手动去new的假如项目中有很多的地方使用了【2代引擎】,要换成【3代引擎】,即把全部的new EngineV1()改成new EngineV2()。
- 我们可以先创建出一个仓库来,把引擎先创建好放在容器里,车辆需要的时候直接从仓库里取。
代码如下:
容器
public class Container {
private Map<String , Object> map = new HashMap<String , Object>();
public Container () {
map.put("engine" , new EngineV2());
}
public Object getBean (String key) {
return map.get(key);
}
}
测试
public class Test3 {
public static void main(String[] args) {
Container container = new Container();
Car car = new Car((IEngine) container.getBean("engine"));
car.info();
Van van = new Van((IEngine) container.getBean("engine"));
van.info();
}
}
可以看到,如果这时候需要把【2代引擎】换成【3代引擎】,只需要修改一处地方即可。map.put("engine", new EngineV2());
总结
这就是IOC做的事情,把创建对象的过程交给容器管理,我们需要用的时候直接拿就行。以前我们在代码中,使用new 构造方法创建对象,现在不用了, 由容器代替开发人员管理对象。