1. 程式人生 > >深入剖析Spring(一)——IoC的基本概念(從面向物件角度介紹)

深入剖析Spring(一)——IoC的基本概念(從面向物件角度介紹)

這裡寫圖片描述

IoC與DI

IoC和DI是Spring的兩個核心概念,很多人都把它們視為相同的東西,但事實並非如此。
IoC(Inversion of Control):控制反轉。
DI(Dependency Injection):依賴注入。

為了方便理解,先給出結論:

控制反轉是目的,依賴注入是實現控制反轉的手段。

控制反轉是一種面向物件的思想,它是一種寬泛的概念,只要一個類將對它內部狀態的控制權交由其他機制去完成即為『控制反轉』。控制反轉是為了降低類與類之間的耦合度。

而Spring採用依賴注入這一具體的手段來達到控制反轉的目的。

依賴注入詳解
一個類內部往往有很多成員變數,如:

class A {
    private Person chaimm;
}

上述程式碼在面向物件中可以描述為:

  • A類和Person類之間存在依賴關係;
  • A依賴於Person;
  • A為依賴類;
  • Perosn為被依賴類;

通常情況下,依賴類需要自己去建立並維護被依賴類的物件,如:

class A {
    private Person chaimm = new Person();
}

但依賴注入的做法是:將被依賴物件的建立與維護工作交由專門的機構,而依賴類中只需要宣告所需要的成員變數。
也就是說,依賴類原本需要主動去獲取物件,但採用依賴注入後物件由第三方機構提供,自己僅需宣告需要什麼物件即可。
這樣做的目的就是為了降低兩個類之間的耦合程度。
PS:在Spring中,那個建立、管理物件的機構就稱為『IoC Service Provider』。

但此時還沒體現出依賴注入能降低耦合度這一點,只有當依賴注入與面向介面程式設計結合起來,才能真正發揮依賴注入的優勢。接下來先介紹一下『面向介面程式設計』。

什麼是面向介面程式設計?
一個類依賴其他類的目的是為了獲取其他類所提供的服務,可能這種服務有多種實現,我們可能需要根據不同的場景使用不同的實現。此時,我們可以使用多型,將同一功能的多種實現抽象出一個介面,併為所有實現定義一套相同的API。在使用時宣告介面型別的變數而非實現類的變數,並將實現類的物件賦給介面變數,最後用介面變數去呼叫實現類的服務,如:

class A {
    private Super super = new SuperImpl_1();

    public
static void main ( String[] args ) { // 使用Super提供的服務 super.method_1(); super.method_2(); super.method_3(); } }

這樣,當想使用SuperImpl_2提供的功能時,只需替換Super的實現類,其他地方不做任何變化:

private Super super = new SuperImpl_2();

上述過程就是面向介面程式設計的思想:若某一類服務有多種不同的實現,我們需要抽象出一個介面,並在介面中定義一套API。在使用時宣告介面型別變數,並用實現類的物件賦值。接下來通過介面型別的變數呼叫服務即可。當功能發生變化時,僅需替換實現類即可。

在面向介面程式設計的基礎上使用依賴注入的好處
上述過程如果要換一種實現,就必須要修改A類的程式碼,再重新編譯。而使用了依賴注入後,由於依賴類不需要自己建立維護被依賴物件,該過程由IoC Service Provider完成。因此,當需要替換實現類時,只需在IoC Service Provider中修改,被依賴類、依賴類都不會受到影響,此時這兩個類是鬆耦合的。

依賴注入的三種方式

下面介紹三種方式,將被依賴物件注入給依賴類。

1. 構造器注入

將被依賴物件通過建構函式的引數注入給依賴物件,並且在初始化物件的時候注入。

優點:
物件初始化完成後便可獲得可使用的物件。

缺點:
1. 當需要注入的物件很多時,構造器引數列表將會很長;
2. 不夠靈活。若有多種注入方式,每種方式只需注入指定幾個依賴,那麼就需要提供多個過載的建構函式,麻煩。

2. setter方法注入

IoC Service Provider通過呼叫成員變數提供的setter函式將被依賴物件注入給依賴類。

優點:
靈活。可以選擇性地注入需要的物件。

缺點:
依賴物件初始化完成後由於尚未注入被依賴物件,因此還不能使用。

3. 介面注入

依賴類必須要實現指定的介面,然後實現該介面中的一個函式,該函式就是用於依賴注入。該函式的引數就是要注入的物件。
介面注入中,介面的名字、函式的名字都不重要,只要保證函式的引數是要注入的物件型別即可。

缺點:
侵入行太強,不建議使用。

PS:什麼是侵入行?
如果類A要使用別人提供的一個功能,若為了使用這功能,需要在自己的類中增加額外的程式碼,這就是侵入性。

這裡寫圖片描述