IOC

351 阅读3分钟
控制反转(IOC)是一种思想,依赖注入(DI)是控制反转的一种实现方式。IOC可以实现解耦。

什么是依赖?

如果一个类A的功能实现要借助B,那么就叫B是A的依赖,则称作A依赖于B。比如说,一个人喜欢看视频,而他看视频需要借助手机来实现,则称他依赖于手机。

依赖倒置原则

  1. 上层模块不应该依赖底层模块,它们都应该依赖于抽象
  2. 抽象不应该依赖于细节,细节应该依赖于抽象。

举个例子:

public class Person {

    private Bike mBike;

    public Person() {
        mBike = new Bike();
    }

    public void chumen() {
        System.out.println("出门了");
        mBike.drive();
    }

}

public class Test1 {

    public static void main(String[] args) {
        Person person = new Person();

        person.chumen();
    }

}

一个Person类,他有一个chumen()方法,Person依赖于Bike类,借助BIke来实现chumen()。

现在我们想换成Car作为交通工具。

public class Person {

    private Bike mBike;
    private Car mCar;

    public Person() {
        //mBike = new Bike();
        mCar = new Car();
    }

    public void chumen() {
        System.out.println("出门了");
        //mBike.drive();
        mCar.drive();
    }

}

这样,我们每次想要修改出门方式的时候,就要在Person类中修改大量的代码,当项目过于庞大时,会很难进行维护。我们应该遵循依赖倒置的原则。

即:上层模块应该依赖于抽象。

因此,定义一个接口。

public interface Driveable {
    void drive();
}

各种交通工具,Car,Bike等都来实现这个类。这是,Person类应该这样定义。

public class Person {

//  private Bike mBike;
//  private Car mCar;
//  private Train mTrain;
    private Driveable mDriveable;

    public Person() {
        //mBike = new Bike();
        //mCar = new Car();
        //mTrain = new Train();
        mDriveable = new Train();
    }

    public void chumen() {
        System.out.println("出门了");
        //mBike.drive();
        //mCar.drive();
        //mTrain.drive();
        mDriveable.drive();
    }

}

这样,当我们想要修改交通工具时,只需要修改 mDriveable = new Train();这一行代码即可。

上面的内容就是依赖倒置原则。

有人会考虑到倒置这个词,个人的理解是倒置是改变的意思。

本来正常编码下,肯定会出现上层依赖底层的情况,而依赖倒置原则的应用则改变了它们之间依赖的关系,它引进了抽象。上层依赖于抽象,底层的实现细节也依赖于抽象,所以依赖倒置我们可以理解为依赖关系被改变,如果非常纠结于倒置这个词,那么倒置的其实是底层细节,原本它是被上层依赖,现在它倒要依赖与抽象的接口。

控制反转

虽然,我们实现了依赖倒置,更改出行方式很方便,但是每次更改出行方式的时候,Person 这个类还是要修改。Person还是自己掌管着接口的实例化。这样,程序也就不方便维护。因此,我们将Person对Drivable的控制权剥离出来,交给第三方


public class Person {

    private Driveable mDriveable;

    public Person(Driveable driveable) {

        this.mDriveable = driveable;
    }

    public void chumen() {
        System.out.println("出门了");

        mDriveable.drive();
    }

}

public class Test1 {
     public static void main(String[] args) {
        // TODO Auto-generated method stub
        Bike bike = new Bike();
        Car car = new Car();
        Train train = new Train();
//      Person person = new Person(bike);
//      Person person = new Person(car);
        Person person = new Person(train);
        person.chumen();

    }

}

这里我们相当于把控制权交给了Test1这个类。也就是说 Person 只关心依赖提供的功能,但并不关心依赖的创建。Person 不再亲自创建 Driveable 对象,它将依赖的实例化的权力交接给了 Test1。

A对B的控制权抽离出来,将控制权交给第三方,这就是控制反转。依赖注入是控制反转最典型的实现方法。将控制权交给IOC容器,通过构造方法,属性或者工厂模式来将类B注入到A中。

依赖倒置是面向对象开发领域中的软件设计原则,它倡导上层模块不依赖于底层模块,抽象不依赖细节。依赖反转是遵守依赖倒置这个原则而提出来的一种设计模式,它引入了 IoC 容器的概念。依赖注入是为了实现依赖反转的一种手段之一。它们的本质是为了代码更加的“高内聚,低耦合”。