回答

18

依賴注入指的是告訴類的依賴關係是什麼樣的模式,而不是要求類知道在哪裏找到它的所有依賴關係。

因此,舉例來說,你從這個去:

public class UserFetcher { 
    private final DbConnection conn = 
     new DbConnection("10.167.1.25", "username", "password"); 

    public List<User> getUsers() { 
     return conn.fetch(...); 
    } 
} 

到這樣的事情:

public class UserFetcher { 
    private final DbConnection conn; 

    public UserFetcher(DbConnection conn) { 
     this.conn = conn; 
    } 

    public List<User> getUsers() { 
     return conn.fetch(...); 
    } 
} 

這降低耦合的代碼,這是非常有用的,如果你想進行單元測試UserFetcher。現在,您可以將DbConnection傳遞給測試數據庫,而不是運行10.167.1.25的數據庫,而不是UserFetcher總是。或者,在快速測試中更加有用,您可以傳入一個DbConnection的實現或子類,它甚至不連接到數據庫,它只是丟棄請求!

但是,這種原始依賴注入使得佈線(提供與它的依賴的對象)更加困難,因爲你已經替換爲使依賴訪問使用全局變量(本地實例化的對象或)的依賴性圍繞整個對象圖。

想象一下UserFetcherAccountManager的依賴關係,其依賴於AdminConsole。然後AdminConsole需要的DbConnection實例傳遞給AccountManager,並AccountManager需要將它傳遞給UserFetcher ... 即使沒有AdminConsole也不AccountManager需要直接使用DbConnection

控制容器的反轉(春,吉斯等)的目的是通過自動佈線(提供)的依賴關係,使依賴注入容易。要做到這一點,你告訴你的IoC容器一次如何提供一個對象(在Spring中,這稱爲bean),並且每當另一個對象請求該依賴關係時,它將由容器提供。

所以我們的最後一個例子可能看起來像這樣與吉斯,如果我們使用構造器注入:

public class UserFetcher { 
    private final DbConnection conn; 

    @Inject //or @Autowired for Spring 
    public UserFetcher(DbConnection conn) { 
     this.conn = conn; 
    } 

    public List<User> getUsers() { 
     return conn.fetch(...); 
    } 
} 

我們必須要配置的IoC容器。在Guice中,這是通過執行Module完成的;在Spring中,通常通過XML配置應用程序上下文

public class MyGuiceModule extends AbstractModule {  
    @Override 
    public void configure() { 
     bind(DbConnection.class).toInstance(
      new DbConnection("localhost", "username", "password")); 
    } 
} 

現在,當UserFetcher由吉斯或Spring構造時,DbConnection被自動提供。

Guice有a really good Wiki article關於依賴注入背後的動機,並進一步使用IoC容器。這是值得一讀的。

策略模式是依賴注入,在那裏你注入邏輯而不是一個對象(即使在Java中,邏輯將在對象封裝)的一個特例。這是一種解耦獨立業務邏輯的方式。

例如,你可能有這樣的代碼:

public Currency computeTotal(List<Product> products) { 
    Currency beforeTax = computeBeforeTax(products); 
    Currency afterTax = beforeTax.times(1.10); 
} 

但是,如果你想這個代碼擴展到一個新的司法管轄區,以不同的銷售稅方案?您可以注入計算稅的邏輯,如下所示:

public interface TaxScheme { 
    public Currency applyTax(Currency beforeTax); 
} 

public class TenPercentTax implements TaxScheme { 
    public Currency applyTax(Currency beforeTax) { 
     return beforeTax.times(1.10); 
    } 
} 

public Currency computeTotal(List<Product> products, TaxScheme taxScheme) { 
    Currency beforeTax = computeBeforeTax(products); 
    Currency afterTax = taxScheme.applyTax(beforeTax); 
    return afterTax; 
} 
2

控制反轉意味着運行時框架將所有組件連接在一起(例如Spring)。依賴注入是IoC的一種形式(我不知道是否存在另一種形式的IoC)(請參見:http://en.wikipedia.org/wiki/Inversion_of_control)。

策略模式是一種設計模式(由GoF定義),其中算法可以被另一個替換(參見:http://en.wikipedia.org/wiki/Strategy_pattern)。這是通過提供幾個相同接口的實現來存檔的。當使用類似Spring的IoC時,如果您有多個接口實現,並且您可以通過配置從實現切換到另一個實現,那麼您正在使用策略模式。