什么是IoC

IoC,(Inversion of Control),即控制反转。那么究竟什么是控制反转?网络上面搜索这个问题,可以搜索到一大堆的新概念、名词,有的甚至直接从官网机器翻译后贴出来,反而让人更晕。
要理解控制反转,那么首先要知道什么是”正常的”控制。先是有正常的控制,然后才会有“反转”的概念,对吧?

房东控制房屋

例如,现在有一个房东,手上有A、B、C三套房子需要出租。
定义一个房子的接口:

public interface House {
    /**
     * 每一个房子都必须有一个房屋描述
     */
    public String describe();
}

里面有一个describe的方法,即房屋描述。
下面有A、B、C三套房子:

房子A

public class HouseA implements House{
    private String description = "双层挑高入户大堂,园林设计独一无二";
    @Override
    public String describe() {
        return description;
    }
}

房子B

public class HouseB implements House{
    private String description = "高层住宅+洋房,打造复合型低密院落";
    @Override
    public String describe() {
        return description;
    }
}

房子C

public class HouseC implements House {
    private String description = "毗邻千亩湿地公园,5分钟距离接驳多家名校";
    @Override
    public String describe() {
        return description;
    }
}

那么,一般的情况是,由房东来选择一套房子进行描述:

public class Landlord {
    public void advertise() {
        House house = new HouseA();
        System.out.println(house.describe());
    }
}

可以看到,房东选择了房子A来进行描述,那么在租户那里:

public class Tenant {
    public static void main(String[] args) {
        Landlord landlord = new Landlord();
        landlord.advertise();
    }
}

可以看到,对于租户来说,他遇到了一个房东,然后房东向他推销房子A。在这种情况下,租户能够看到哪套房子的决定权,或者说控制权,在房东的手中。

控制反转到租户手中

那么,现在问题来了。如果租户是一个很有主见的人,或者说他希望选房的控制权掌握在自己的手中,即“不要告诉我有哪样的房子,我会告诉你我需要什么样的房子”。此时,由租户决定想租什么样的房子后告诉房东,然后房东再按照租户的需求拿出房子。
那么,对于房东类来说,之前的构造方式:

House house = new HouseA();

一定没法用了。
因为现在的控制权在租户手中,房东现在并不知道租户要哪一套房子,所以自己不能主动的去“创建”一套房子,而是根据租户的需求来“创建”房子。
而房子,作为目前需求中租户所依赖的物品,被称为“依赖对象”。这个词其实很好理解,比如我是一个刚毕业的大学生,我要居住,我要生活,而这些都需要“依赖”房子这个东西。在Java的世界里,“万物皆对象”,所以房子在这里被称为“依赖对象”。
所以,现在的依赖对象(即房子)对于房东来只是作为一个参数传入,而非先前的主动构造,即:

public class Landlord {
    House house;
    public Landlord(House house) {
        this.house = house;
    }
    public void advertise(House house) {
        System.out.println(house.describe());
    }
}

那么现在在租户那里,是由他来选择哪套房去创建,假如租户现在需要房子B的信息:

public class Tenant {
    public static void main(String[] args) {
        House house = new HouseB();
        Landlord landlord = new Landlord(house);
        landlord.advertise();
    }
}

假设租户需要房子C的信息:

public class Tenant {
    public static void main(String[] args) {
        House house = new HouseC();
        Landlord landlord = new Landlord(house);
        landlord.advertise();
    }
}

由此可以发现,房子还是那三套房子,先前是由房东控制获取哪一套,现在是由租户控制获取哪一套。获得依赖对象的过程被反转了,这就叫“控制反转”

控制反转,就是获得依赖对象的过程被反转。

控制反转是思想,Spring Framework实现了这种思想

有人可能要问了,这与Spring Framework有什么关系?当然与Spring Framework没有任何关系。控制反转只是一种思想,而Spring Framework是现实了这种思想。你也可以自己编写一套框架,去实现控制反转;或者哪天Spring宣布新版本不再实现控制反转(当然这不太可能,哈哈)。所以千万不要把控制反转和Spring Framework强联系起来,他们只是一个是思想、而一个现实了这种思想的关系。
所以,人家面试官面试的时候问“Spring Framework是什么”的时候,千万不要再回答“Spring就是IoC和AOP”;或者,人家问“控制反转是什么”的时候,千万不要再回答“控制反转是Spring Framework的两大特性之一”。

构造器注入和setter注入

刚才Landlord(房东)类中注入House(房子)类的方式,叫构造器注入,即利用Landlord类的构造方法注入房子。
下面这种方式,叫setter注入,即利用Landlord类的setter方法注入:

public class Landlord {
    House house;
    public void setHouse(House house) {
        this.house = house;
    }
    public void advertise() {
        System.out.println(house.describe());
    }
}

然后在用户类中,进行setter注入:

public class Tenant {
    public static void main(String[] args) {
        House house = new HouseC();
        Landlord landlord = new Landlord();
        landlord.setHouse(house);
        landlord.advertise();
    }
}

可以看出,两种方式实现的方法不同,但是本质思想是一样的。
这里,只讲定义,后面会详细阐述这二者间的区别和使用。


何舜
2 声望4 粉丝

Java开发工程师