Changes between Initial Version and Version 1 of waue/2011/spring


Ignore:
Timestamp:
Aug 24, 2011, 3:15:16 PM (13 years ago)
Author:
waue
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • waue/2011/spring

    v1 v1  
     1IoC模式基本上是一個高層的概念,在 Martin Fowler 的 Inversion of Control Containers and the Dependency Injection pattern 中談到,實現IoC有兩種方式:Dependency Injection與Service Locator,Spring 所採用的是Dependency Injection 來實現 IoC,中文翻譯為依賴注入,依賴注入的意義是:「保留抽象介面,讓組件依賴於抽象介面,當組件要與其它實際的物件發生依賴關係時,藉過抽象介面來注入依賴的實際物件。」
     2
     3看看下面這個程式:
     4{{{
     5#!java
     6public class BusinessObject {
     7    private FloppyWriter writer = new FloppyWriter();
     8    ....
     9   
     10    public void save() {
     11        ...
     12        writer.saveToFloppy();
     13
     14    }
     15}
     16}}}
     17BusinessObject 依賴於實際的 FloppyWriter,為了讓 BusinessObject 獲得重用性,不讓 BusinessObject 直接依賴於實際的 FloppyWriter,而是依賴於抽象的介面:
     18
     19{{{
     20#!java
     21public interface IDeviceWriter {
     22    public void saveToDevice();
     23}
     24
     25public class BusinessObject {
     26    private IDeviceWriter writer;
     27
     28    public void setDeviceWriter(IDeviceWriter writer) {
     29        this.writer = writer;
     30    }
     31
     32    public void save() {
     33        ....
     34        writer.saveToDevice();
     35    }
     36}
     37
     38public class FloppyWriter implement IDeviceWriter {
     39    public void saveToDevice() {
     40        ....
     41        // 實際儲存至Floppy的程式碼
     42    }
     43}
     44
     45public class UsbDiskWriter implement IDeviceWriter {
     46    public void saveToDevice() {
     47        ....
     48        // 實際儲存至UsbDisk的程式碼
     49    }
     50}
     51}}}
     52
     53如果今天BusinessObject想要與UseDiskWriter物件發生依賴關係,可以這麼建立:
     54businessObject.setDeviceWriter(new UsbDiskWriter());
     55
     56
     57由於BusinessObject依賴於抽象介面,在需要建立依賴關係時,可以透過抽象介面注入依賴的實際物件。
     58
     59依賴注入在Martin Fowler的文章中談到了三種實現方式:Interface injection、Setter injection 與 Constructor injection。並分別稱其為Type 1 IoC、Type 2 IoC 與 Type 3 IoC。
     60
     61上面的BusinessObject所實現的是Type 2 IoC,透過Setter注入依賴關係,而Type 3 IoC,則在是建構式上注入依賴關係,例如:
     62{{{
     63#!java
     64public class BusinessObject {
     65    private IDeviceWriter writer;
     66
     67    public BusinessObject(IDeviceWriter writer) {
     68        this.writer = writer;
     69    }
     70
     71    public void save() {
     72        ....
     73        writer.saveToDevice();
     74    }
     75}
     76}}}
     77
     78Spring 鼓勵的是 Setter injection,但也允許您使用 Constructor injection,使用 Setter 或 Constructor 來注入依賴關係視您的需求而定,使用 Constructor 的好處之一是,您可以在建構物件的同時一併完成依賴關係的建立,然而如果要建立的物件關係很多,則會在建構式上留下一長串的參數,這時使用 Setter 會是個不錯的選擇,另一方面,Setter 可以有明確的名稱可以瞭解注入的物件會是什麼,像是setXXX()這樣的名稱會比記憶Constructor上某個參數位置代表某個物件來得好。
     79
     80Type 1 IoC是Interface injection,使用Type 1 IoC時會要求實作介面,這個介面是為容器所用的,容器知道介面上所規定的方法,它可以呼叫實作介面的物件來完成依賴關係的注入,例如:
     81{{{
     82#!java
     83public interface IDependencyInjection {
     84    public void createDependency(Map dependObjects);
     85}
     86
     87public class BusinessObject implement IDependencyInjection {
     88    private Map dependObjects;
     89
     90    public void createDependency(Map dependObjects) {
     91        this.dependObject = dependObjects;
     92        // 在這邊實現與BusinessObject的依賴關係
     93        ......
     94    }
     95
     96    public void save() {
     97        ....
     98        writer.saveToDevice();
     99    }
     100}
     101}}}
     102
     103如果要完成依賴關係注入的物件,必須實現IDependencyInjection介面,並交由容器管理,容器會呼叫被管理物件的createDependency()方法來完成依賴關係的建立。
     104
     105在上面的例子中,Type 1 IoC要求BusinessObject實現特定的介面,這就使得BusinessObject依賴於容器,如果日後BusinessObject要脫離目前這個容器,就必須修改程式,想想在更複雜的依賴關係中產生更多複雜的介面,組件與容器(框架)的依賴會更加複雜,最後使得組件無法從容器中脫離。
     106
     107所以Type 1 IoC具有強的侵入性,使用它來實現依賴注入會使得組件相依於容器(框架),降低組件的重用性。
     108
     109Spring的核心是個IoC容器,您可以用Setter或Constructor的方式來實現您的業務物件,至於物件與物件之間的關係建立,則透過組態設定,讓Spring在執行時期根據組態檔的設定來為您建立物件之間的依賴關係,您不必特地撰寫一些Helper來自行建立這些物件之間的依賴關係,這不僅減少了大量的程式撰寫,也降低了物件之間的耦合程度。