1. 程式人生 > 其它 >依賴注入淺析

依賴注入淺析

一、起因

首先說起依賴注入,是為了解決類與類之間關聯性太強,耦合度太高。如果一個高階類(A類)中包含另一個低階類(b類),傳統方式,是在A類中初始化b類。即:

public class A
{
    private b b1   = new b();
}

這樣A類要維護b類的生命週期(建立,銷燬)。而且在A類的外部根本看不到其內部的具體依賴物件,無從考究他內在的依賴物件,造成A類處於一個比較複雜的狀態。

如果要降低A類與b類的關聯性,需要把b類暴露出去,讓其他外部成員可以看到A類具體依賴的物件。所以:

public class A
{
    private b b_1;
    public A(b b1)
    {
         b_1 = b1;
    }
}    

現在,如果初始化A類的時候,看到其內部具體依賴的物件是b(建構函式建立時需要傳入b例項),A類只維護b例項的引用,不負責建立和銷燬工作(通過外部進行)。現在還是有些缺陷,就是A類仍然依賴b例項,和b例項還是有著強耦合。b例項有具體的實現,假如更換成抽象,A類與抽象的關聯,抽象再與b例項關聯(“沒有什麼事情是加一箇中間層解決不了的”)。這樣依賴就變成了兩個,這怎麼變複雜了?本來的一個依賴,變成兩個了。雖然是變複雜了,但是A類與b例項的關聯關係就變弱了,而且可以隨時替換b類(換成c,d...)。

interface ib
{
}

public class b:ib
{
}

public class A
{
   private ib b_1;
   public A(ib b1)
   {
       b_1 = b1;
   }
}

這樣就看起來完美了,A類不再依賴b類了,變成基於抽象的程式設計了。但是外部仍然需要有個初始化的類給我們傳入,如果在外部構造一個傳入,不同樣是把內部的耦合轉到外部去了嗎,仍然不好。這時候就需要第三方工具幫助我們建立類例項,不能我們自己在程式碼中都是new。

二、方案

管理例項化和管理物件責任的方法一共有三種:工廠,服務定位器和依賴注入。他們都各有優缺點。

1、工廠模式

public class three
{
     public virtual ib Createb()
     {
          return new b();
     }          
}

現在把b例項建立通過第三方工廠進行建立。只需通過呼叫第三方方法就可以。不同的抽象實現只需要繼承three工廠類修改重寫建立方法就行。

2、服務定位模式

使用服務定位器為使用另一個類代表您建立物件的一般方法提供了另一種變體。您可以將服務定位器視為一個登錄檔,您可以在其中查詢應用程式中的另一個類建立並向服務定位器註冊的物件或服務的例項。服務定位器可能支援通過字串鍵或介面型別查詢物件。通常,與工廠模式不同的是,工廠建立物件,但將管理其生存期的責任交給客戶機類,服務定位器負責管理物件的生存期,並簡單地向客戶機返回一個引用。此外,工廠通常負責建立特定型別或型別族的例項,而服務定位器可能能夠返回對應用程式中任何型別的物件的引用。使用服務定位器時,每個類都將依賴於您的服務定位器。

3、依賴注入

所有工廠模式和服務定位器模式的一個共同特徵是,高階客戶機物件仍然負責通過請求所需型別的特定例項來解決其自身的依賴關係。它們各自採用一種複雜程度不同的拉動模型,將各種責任分配給工廠或服務定位器。pull模型還意味著高階客戶機類依賴於負責建立或定位它想要使用的物件的類。這也意味著高階客戶機類的依賴項隱藏在這些類中,而不是在單個位置指定,這使得它們更難測試。

依賴注入採用相反的方法,採用推模型代替拉模型。控制反轉是一個經常用來描述這種推送模型的術語,依賴注入是控制反轉技術的一個具體實現。 對於服務定位器,應用程式類通過給定位器的訊息顯式地請求它。使用注入時,沒有顯式請求,服務出現在應用程式類中,因此控制反轉。(控制容器反轉和依賴注入模式。) 使用依賴注入,另一個類負責在執行時將依賴注入(推送)到高階客戶機類中。

如果採用依賴項注入方法,應用程式中會有許多類需要其他類或元件將必要的依賴項作為引數或屬性值傳遞到它們的建構函式或方法中,然後才能使用它們。這意味著您的應用程式需要一個類或元件,該類或元件負責例項化所有必需的物件,並將它們傳遞到正確的建構函式、方法和屬性中:您的應用程式在執行任何工作之前必須知道如何組合其物件圖。這必須在應用程式生命週期的早期發生。