Changes between Version 12 and Version 13 of waue/2011/spring


Ignore:
Timestamp:
Aug 25, 2011, 5:14:17 PM (13 years ago)
Author:
waue
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • waue/2011/spring

    v12 v13  
    241241}}}
    242242
    243 從這個角度來看,Dependency Injection 的意思即是程式不依賴於實作,而是程式與實作都要依賴於抽象。
     243從這個角度來看,[wiki:waue/2011/DI Dependency Injection (Detail)] 的意思即是程式不依賴於實作,而是程式與實作都要依賴於抽象。
    244244
    245245IoC 的 Control 是控制的意思,其實其背後的意義也是一種依賴關係的轉移,如果A依賴於B,其意義即是B擁有控制權,您想要轉移這種關係,所以依賴關係的反轉即是控制關係的反轉,藉由控制關係的轉移,可以獲得元件的可重用性,在上面的 Java 程式中,整個控制權從實際的 FloppyWriter 轉移至抽象的 IDeviceWriter 介面上,使得BusinessObject、FloppyWriter、UsbDiskWriter 這幾個實現依賴於抽象的 IDeviceWriter 介面。
     
    249249IoC 在容器的角度,可以用這麼一句好萊塢名言來代表:"Don't call me, I'll call you." 以程式的術語來說的話,就是「不要向容器要求您所需要的(物件)資源,容器會自動將這些物件給您!」。IoC 要求的是容器不侵入應用程式本身,應用程式本身提供好介面,容器可以透過這些介面將所需的資源注至至程式中,應用程式不向容器主動要求資源,故而不會依賴於容器的元件,應用程式本身不會意識到正被容器使用,可以隨時從容器中脫離轉移而不用作任何的修改,而這個特性正是一些業務邏輯中間件最需要的。
    250250
    251  == Dependency Injection ==
    252 
    253 Spring 所採用的是Dependency Injection 來實現 IoC,中文翻譯為依賴注入
    254 
    255 依賴注入的意義是:「保留抽象介面,讓組件依賴於抽象介面,當組件要與其它實際的物件發生依賴關係時,藉過抽象介面來注入依賴的實際物件。」
    256 
    257 依賴注入在Martin Fowler的文章中談到了三種實現方式:
    258  * Interface injection (Type 1 IoC )
    259  * Setter injection (Type 2 IoC )
    260  * Constructor injection ( Type 3 IoC )
    261 
    262 上面的BusinessObject所實現的是Type 2 IoC,透過Setter注入依賴關係,
    263 
    264  == Type 2 IoC : Setter injection ==
    265 
    266 BusinessObject 依賴於實際的 FloppyWriter,為了讓 BusinessObject 獲得重用性,不讓 BusinessObject 直接依賴於實際的 FloppyWriter,而是依賴於抽象的介面,複習一下 IoC 該節的例子(同上):
    267 {{{
    268 #!java
    269 public interface IDeviceWriter {
    270     public void saveToDevice();
    271 }
    272 
    273 public class BusinessObject {
    274     private IDeviceWriter writer;
    275 
    276     public void setDeviceWriter(IDeviceWriter writer) {
    277         this.writer = writer;
    278     }
    279 
    280     public void save() {
    281         ....
    282         writer.saveToDevice();
    283     }
    284 }
    285 
    286 public class FloppyWriter implement IDeviceWriter {
    287     public void saveToDevice() {
    288         ....
    289         // 實際儲存至Floppy的程式碼
    290     }
    291 }
    292 
    293 public class UsbDiskWriter implement IDeviceWriter {
    294     public void saveToDevice() {
    295         ....
    296         // 實際儲存至UsbDisk的程式碼
    297     }
    298 }
    299 
    300 }}}
    301 
    302 如果今天BusinessObject想要與UseDiskWriter物件發生依賴關係,可以這麼建立:
    303 {{{
    304 #!java
    305 businessObject.setDeviceWriter(new UsbDiskWriter());
    306 }}}
    307 
    308 由於BusinessObject依賴於抽象介面,在需要建立依賴關係時,可以透過抽象介面注入依賴的實際物件。
    309 
    310  == Type 3 IoC : Constructor injection ==
    311 
    312 Type 3 IoC,則在是建構式上注入依賴關係,例如:
    313 {{{
    314 #!java
    315 public class BusinessObject {
    316     private IDeviceWriter writer;
    317 
    318     public BusinessObject(IDeviceWriter writer) {
    319         this.writer = writer;
    320     }
    321 
    322     public void save() {
    323         ....
    324         writer.saveToDevice();
    325     }
    326 }
    327 }}}
    328 
    329 Spring 鼓勵的是 Setter injection,但也允許您使用 Constructor injection,使用 Setter 或 Constructor 來注入依賴關係視您的需求而定,使用 Constructor 的好處之一是,您可以在建構物件的同時一併完成依賴關係的建立,然而如果要建立的物件關係很多,則會在建構式上留下一長串的參數,這時使用 Setter 會是個不錯的選擇,另一方面,Setter 可以有明確的名稱可以瞭解注入的物件會是什麼,像是setXXX()這樣的名稱會比記憶Constructor上某個參數位置代表某個物件來得好。
    330 
    331  == Type 1 IoC : Interface injection ==
    332 
    333 Type 1 IoC是Interface injection,使用Type 1 IoC時會要求實作介面,這個介面是為容器所用的,容器知道介面上所規定的方法,它可以呼叫實作介面的物件來完成依賴關係的注入,例如:
    334 {{{
    335 #!java
    336 public interface IDependencyInjection {
    337     public void createDependency(Map dependObjects);
    338 }
    339 
    340 public class BusinessObject implement IDependencyInjection {
    341     private Map dependObjects;
    342 
    343     public void createDependency(Map dependObjects) {
    344         this.dependObject = dependObjects;
    345         // 在這邊實現與BusinessObject的依賴關係
    346         ......
    347     }
    348 
    349     public void save() {
    350         ....
    351         writer.saveToDevice();
    352     }
    353 }
    354 
    355 }}}
    356 如果要完成依賴關係注入的物件,必須實現IDependencyInjection介面,並交由容器管理,容器會呼叫被管理物件的createDependency()方法來完成依賴關係的建立。
    357 
    358 在上面的例子中,Type 1 IoC要求BusinessObject實現特定的介面,這就使得BusinessObject依賴於容器,如果日後BusinessObject要脫離目前這個容器,就必須修改程式,想想在更複雜的依賴關係中產生更多複雜的介面,組件與容器(框架)的依賴會更加複雜,最後使得組件無法從容器中脫離。
    359 
    360 所以Type 1 IoC具有強的侵入性,使用它來實現依賴注入會使得組件相依於容器(框架),降低組件的重用性。
    361 
    362 Spring的核心是個IoC容器,您可以用Setter或Constructor的方式來實現您的業務物件,至於物件與物件之間的關係建立,則透過組態設定,讓Spring在執行時期根據組態檔的設定來為您建立物件之間的依賴關係,您不必特地撰寫一些Helper來自行建立這些物件之間的依賴關係,這不僅減少了大量的程式撰寫,也降低了物件之間的耦合程度。
    363