IOC思想

45 阅读3分钟

概念

控制反转(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 构造方法创建对象,现在不用了, 由容器代替开发人员管理对象。