微軟模式與實踐小組發布了叫做Unity或者Unity Application Block的依賴注入容器。開發人員現在能夠利用可擴展的輕量級容器創建松耦合應用。
InfoQ有機會采訪了Unity項目的開發領頭人Chris Tavares。
Rob Bazinet (RB): Chris介紹一下你自己和你是如何參與Unity的?
Chris Tavares (CT):我的名字叫Chris Tavares。我是微軟模式與實踐小組的一名高級軟件開發人員。我目前正在領導Enterprise Library 4和Unity Application Block的開發。我也寫了大部分的Unity的代碼,所以Unity的美麗都源於我的“錯誤”。我已經在模式與實踐小組工作超過2年時間。在來微軟工作之前,我從90年代開始從事工業軟件外包,盒裝軟件開發,甚至一些嵌入式軟件開發。
RB:Unity Application Block是什麼?
CT:Unity是一個依賴注入(Dependency Injection,DI)容器。DI的標准描述文章來自Martin Flower[0]【譯者注:中文譯文參見[4]】。作為一個快速的摘要,依賴注入容器就是一個用於構建高度松耦合的軟件的工具。依賴注入容器處理相互關聯對象的所有細節,因此你可以構建一個獨立的組件。這對可測試性和靈活性方面有很大的影響。
例如在一個銀行系統的,你可以有一個對象,管理帳戶轉帳。要實現這個目標,需要獲得個人賬戶的對象,再加上安全規則及審計方面的要求。通常的實現看起來是這樣的:
AccountTransfer
{
TransferMoney( sourceAccountNumber, destAccountNumber, amount)
{
Account sourceAccount = AccountDatabase.GetAccount(sourceAccountNumber);
Account destAccount = AccountDatabase.GetAccount(destAccountNumber);
sourceAccount.Withdraw(amount);
destAccount.Deposit(amount);
Logger.Write(, amount, sourceAccountNumber, destAccountNumber);
}
}
可以想象,這是相當可怕的代碼(例如沒有事務管理),雖然其可以正常工作。;-)
這是很簡單的,但也是高度耦合的。全局的AccountDatabase 類調用意味著你甚至不能單獨編譯,更別提進行測試了。如果帳號是來自兩個不同的銀行會發生什麼呢?同樣的,全局的日志記錄器意味著你必須先獲得一個某個明確全局記錄器類所創建日志記錄器後,才能使用這個類。這一結果在當你嘗試編寫單元測試的時候是很痛苦的,而且從長遠來看也極大地限制了靈活性。
職責分離原則要求一個類不要有多個職責。在這裡,這個類違反了這一原則,不僅關心如何轉移資金的細節,而且還要知道如何從數據庫中獲取帳號和如何寫日志信息。為了恢復靈活性,這些職責需要分離到不同的對象,然後在通過傳遞回這個對象來使用它們,看起來像這樣:
AccountTransfer
{
IAccountRepository accounts;
ILogger logger;
AccountTransfer(IAccountRepository accounts, ILogger logger)
{
.accounts = accounts;
.logger = logger;
}
TransferMoney( sourceAccountNumber, destAccountNumber, amount)
{
Account sourceAccount = accounts.GetAccount(sourceAccountNumber);
Account destAccount = accounts.GetAccount(destAccountNumber);
sourceAccount.Withdraw(amount);
destAccount.Deposit(amount);
logger.Write(, amount, sourceAccountNumber, destAccountNumber);
}
}
這樣更加封閉。現在我們不依賴於外部的全局對象,只是通過構造函數傳遞對象實例。這個類現在可以被單獨測試,甚至可以通過簡單地傳入不同的IAccountRepository實現來和不同銀行進行交互。
不過,現在有了新的代價。AccountTransfer的創建者現在必須知道如何創建所依賴的對象。你使用哪個帳號數據庫?那個日志記錄器?如果這些都是通過配置來建立,例如現在你的代碼依賴於配置並且重新設計。
這就是依賴注入容器責無旁貸的,它是一個智能的對象工廠。你告訴容器如何解決特定對象的依賴關系。例如使用Unity,你可以像這樣配置容器(使用API,也可以支持外部配置文件):
IUnityContainer container = UnityContainer();
container.RegisterType();
container.RegisterType();
這告訴容器”如果一個依賴於IAccountRepository實例的對象,就創建一個ContosoBankRepository實例並使用它,如果任何一個對象需要一個ILogger實例,就給它一個DatabaseLogger。”你現在可以像這樣要求容器給你一個由依賴關系的實例對象:
container.Resolve();
Resolve方法的調用試圖創建一個AccountTransfer實例。容器看到構造函數需要一個IAccountRepository和一個ILogger實例,因此它創建了那些對象(使用先前指定的特定類型)並通過構造函數傳遞給AccountTransfer實例。這是利用容器集中組織你的應用程序的方法。這在你的應用程序中提供了一個地方處理對象之間的掛接,並且釋放了對象圖上單獨對象的構造。由此產生的靈活性無論是可測試性還是靈活性真的是非常值得。如果你的類的依賴關系發生改變,這並不影響對象的創建,只需要配置容器就可以。
RB:Unity是Enterprise Library的一部分還是單獨發布? 從我看過的資料來看,Microsoft Dependency Injection Block是作為Enterprise Library 4.0的一部分來發布的。
CT:Unity是單獨發布的。Enterprise Library 4.0是建立在Unity之上的,你可以通過Unity訪問Enterprise Library的功能。
需要說明一點的是,在Enterprise Library 2和Composite UI Application Block(CAB)發布的時候,這兩個下面的引擎是一個叫做ObjectBuilder的類庫。ObjectBuilder是一個用來構建依賴注入容器的框架。CAB和Enterprise Library都使用ObjectBuilder,但是OB是自己獨立的東西,後來被單獨發布[1]。
新版本的ObjectBuilder是Unity的一部分。Enterprise Library 4還是和以前一樣使用ObjectBuilder:讀取配置並建立適當的Enterprise Library對象。我們也引入了一種新的方式來訪問Enterprise Library的功能,直接通過容器而不是把那種機制隱藏起來。Scott Densmore的一篇博客[2]詳細的描述我們正在計劃的工作細節。
因此,再次重申:Unity是作為一個獨立的整體。Enterprise Library使用了Unity的一部分或者是可通過Unity使用。為了節省下載的麻煩,Enterprise Library包含Unity的二進制程序集。因此如果你關心的是在Enterprise Library中使用,已經為你准備好了,不需要安裝額外的東西。
RB:在什麼環境下,開發人員選擇使用Unity?
CT:第一個問題是你是否想使用依賴注入。如果是的話,我想Unity是一個很好的選擇,但是我也建議你評估一下其他的容器。Scott Hanselman列出了一些現.NET 依賴注入容器項目[3]。
RB:Unity和其他的依賴注入容器有什麼不同以及和他們相比怎麼樣?
CT:從模式與實踐上來說,在這個問題上我要非常小心。我不想給人這樣的印象——不是贊同就是反對人們使用其他的項目。我們強烈建議大家評估自己的選擇,並選擇滿足需要的最好的容器,不管是Unity還是現有的開源項目。
RB:已經有相當多的依賴注入容器,又是什麼動機使得你們團隊創建了Unity?
CT:模式與實踐一直圍繞依賴注入提供指導有一段時間了。CAB、Mobile Client Software Factory、Smart Client Software Factory、Web Client Software Factory和Enterprise Library都以“各種”方式使用依賴注入。最後一個詞“各種”是致命的。雖然每個項目都建立在ObjectBuilder之上,使用依賴注入方式都是不同和不相容地。有一個明確的,功能齊全的容器對於我們圍繞依賴注入提供更好的指導和基於容器的基礎架構。
還有其他的原因,我們有的客戶無論什麼原因,不會去接觸開放源代碼的軟件。擁有一個由微軟提供支持的容器使得他們有更大的安全感,並讓他們得到好處。如果他們將來選擇使用其他的容器也使他們處於有利地位。
另一個目標是提高依賴注入容器在微軟內外的使用。有一個微軟提供的容器有助於依賴注入在廣大微軟.NET社區和微軟內部開發人員的使用。
RB:對於開發者和團隊以最好的方式開始使用Unity有什麼建議?
CT:安裝它並通讀文檔,並從我們已經發布的簡單快速指南開始。
RB:有沒有Unity快速指南和最佳實踐的示例代碼?
CT:我們已經有一個Windows Forms應用(紅綠燈模擬器)小例子,利用容器注入服務。這實在是一個小型和相當容易的例子,包括C#和VB.NET版本代碼。
RB:Unity有什麼計劃?
CT:沒有什麼事一成不變的,當然我個人的目標是增加一些特性(有能力攔截方法調用是列表中最高級別的),以及獲得未來的模式與實踐的資產以規范基於容器的基礎架構。一個更好的文件配置系統。
從長遠來看,我喜歡以合理的方式找一些或者所有這些概念都轉換成核心平台。
RB:Chris,謝謝你接受我們的采訪和這些Unity的重要信息。
從Unity的網站上看,Unity是:
Unity Application Block (Unity)是一個輕量級的, 可擴展的依賴注入容器. 它有助於構建松耦合的應用程序和為開發者提供以下便利:
簡化對象的創建,特別在分層對象結構和依賴的情形下
它支持需求的抽象化,這允許開發人員在運行時或在配置文件中指定依賴,簡化橫切關注點(crosscutting concerns)的管理
它通過把組件配置推給容器來決定,增加了靈活性
服務定位能力; 這使客戶端能夠存儲或緩存容器
查看英文原文:Microsoft Unity Dependency Injection Application Block Released