IoC和DI以及它們的區別

一、IoC

  1. IOC(Inverse of Control):控制反轉,它不是什麼技術,而是一種設計思想。在Java開發中,IoC意味着將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。

  2. 下面從哪些方面被反轉了來理解IoC?
    1、誰控制誰?爲什麼叫反轉? ------ IoC容器控制,而以前是應用程序控制,所以叫反轉
    2、控制什麼? ------ 控制應用程序所需要的資源(對象、文件……)
    3、爲什麼控制? ------ 解耦組件之間的關係
    4、控制的哪些方面被反轉了? ------ 程序的控制權發生了反轉:從應用程序轉移到了IoC容器。

  3. IoC容器特點
    無需主動new對象;由IoC容器創建。
    不需要主動裝配對象之間的依賴關係,而是描述需要哪個服務(組件),IoC容器會幫你裝配(即負責將它們關聯在一起),被動接受裝配;
    主動變被動,好萊塢法則:別打電話給我們,我們會打給你;
    迪米特法則(最少知識原則):不知道依賴的具體實現,只知道需要提供某類服務的對象(面向抽象編程),鬆散耦合,一個對象應當對其他對象有儘可能少的瞭解,不和陌生人(實現)說話
    IoC是一種讓服務消費者不直接依賴於服務提供者的組件設計方式,是一種減少類與類之間依賴的設計原則。

二、DI

  1. DI(Dependency Injection):依賴注入,用一個單獨的對象(裝配器)來裝配對象之間的依賴關係 。

  2. 理解DI問題關鍵
    誰依賴於誰? ------- 應用程序依賴於IoC容器
    爲什麼需要依賴? ------- 應用程序依賴於IoC容器裝配類之間的關係
    依賴什麼東西? ------- 依賴了IoC容器的裝配功能
    誰注入於誰? ------- IoC容器注入應用程序
    注入什麼東西? ------- 注入應用程序需要的資源(類之間的關係)。

  3. DI優點
    幫你看清組件之間的依賴關係,只需要觀察依賴注入的機制(setter/構造器),就可以掌握整個依賴(類與類之間的關係)。
    組件之間的依賴關係由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關係注入到組件之中。
    依賴注入的目標並非爲軟件系統帶來更多的功能,而是爲了提升組件重用的概率,併爲系統搭建一個靈活、可擴展的平臺。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不用關心具體的資源來自何處、由誰實現。

4.DI注入方式

  • 構造器注入
    首先,定義一個Person類
public class Person {
    String name;
    int age;
    Person(String name,int age){
        this.name=name;
        this.age=age;
    }
 
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

配置文件,Beans標籤下加入如下內容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean id="xiaojun" class="main.Person">
        <constructor-arg index="0" value="xiaojun"></constructor-arg>
        <constructor-arg index="1" value="12"></constructor-arg>
    </bean>
    <bean id="xiaohong" class="main.Person">
        <constructor-arg index="0" value="xiaohong"></constructor-arg>
        <constructor-arg index="1" value="11"></constructor-arg>
    </bean>
</beans>

測試代碼

import main.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class PersonTest {
    public static void main(String[] args){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
        Person person = (Person) applicationContext.getBean("xiaojun");
        System.out.println(person.toString());
    }
}

結果如下

Person{name=‘xiaojun’, age=12}
屬性注入
在剛纔Person類基礎上添加set方法(這個是必須的)

public class Person {
    String name;
    int age;
 
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
 
    public void setName(String name) {
        this.name=name;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}

配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean id="xiaojun" class="main.Person">
        <property name="name" value="小山"></property>
        <property name="age" value="22"></property>
    </bean>
</beans>

使用上面的測試方法可得如下結果

Person{name=‘小山’, age=22}
接口注入
定義一個Clothes的枚舉類

public enum Clothes {
     coat,
    T_shirt,
    skirt,
    jeans,
}

不同的人穿不同的衣服,定義一個穿衣服的接口

public interface WearClothes {
    public void wear(Clothes clothes);
}
穿衣服接口的實現類

public class WearClothesImlp implements WearClothes{
    Clothes clothes;
    @Override
    public void wear(Clothes clothes) {
        this.clothes=clothes;
        System.out.println("People wear "+ clothes);
    }
}

通過示例發現,這個接口注入挺像set注入的,只不過把set改名了。
因爲WearClothesImlp類依賴於WearClothes接口,增加了耦合性。所以Spring不支持接口注入。

三、IoC和DI由什麼關係呢?

其實它們是同一個概念的不同角度描述,由於控制反轉概念比較含糊(可能只是理解爲容器控制對象這一個層面,很難讓人想到誰來維護對象關係),所以2004年大師級人物Martin Fowler又給出了一個新的名字:“依賴注入”,相對IoC 而言,“依賴注入”明確描述了“被注入對象依賴IoC容器配置依賴對象”。

四、爲什麼會出現IoC和DI ?

通常我們在一個類的方法內使用另一個類方法,這時候就需要在類方法內創建對象,然後使用該方法。這樣會增加該類對另一類的耦合性。在編程中我們一般建議高內聚,低耦合。所以,當我們使用IoC和DI後,就會發現問題迎刃而解。
Spring框架正式採用這種方法,我們把創建對象的任務交給IoC容器,由IoC容器代替我們進行創建對象的工作。我們無需關係對象設麼時候創建,只需要創建配置文件的容器對象,我們在使用時用getBean方法獲取到該對象就可以了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章