上一周,我們工作小組中有人問我一個問題:為什麼DI(Dependency Injection,依靠性元插入的模式,這是編程中常用的一種模式)十分重要?現在許多編程人員採用OO(Object Oriented,目標編程)的方式。他們以為在一個class中定義數據和接口,將程序中的邏輯包含在其中就足夠了。他們困惑地提出疑問,什麼是DI,為什麼還要採用DI模式?
第二天,我碰到單位中一位資深的編程員,我向他問了一個類似的問題,並問他具體怎麼使用的。他說他只是在對原程序的測試中採用DI,在測試中假設有關讀寫數據庫的變元,這樣不會真正對數據庫產生影響。這是測試中常用的方法,但這並不說明DI的全部。實際上,DI是一個非常重要的概念,而且是編程中常用的一種策略。
用一個形象的比喻,公司里IT部門需要採購部門購買一些硬件,IT按照要求將批準的單子交給採購部門,IT部門不感興趣採購部門的誰去完成這個任務,也不需要了解,部門之間只需要按照之間的交接口進行聯繫和交流。DI編程模式就是按照這樣的方式來編程,“部門”之間不需要知道誰在做具體的工作。
我回憶起我過去所寫的許多項目,並查看我過去的程序。在這裡我對此用一個簡單的例子作具體的解釋。先看看下面的一個C#例子:
public class MyDataReader { ... public bool ReadData() { var dbService = new MyDbService(); .... var data = dbService.GetObject(); .... } }
上面有問題的地方是dbService變元由MyDbService class產生的一行,這種採用new來指定特定class的方式在編程中普遍存在。很明顯MyDataReader class依賴於MyDbService class。換言之,MyDataReader知道所需要的dbService是從那一個class產生的。MyDataReader有必要知道具體創建的class嗎?它只是使用一數據服務通過其接口取得數據(如GetObject()接口),它並不需要知道數據是如何取得的,那麼它關心具體服務的class有必要嗎?如果能夠將這種依賴性分隔,讓一個中介來提供一個數據服務變元,這樣不就更好嗎?
現在我們來看看下面改進的編碼:
public class MyDataReader { ... public bool ReadData() { var dbService = DIContainer.GetInstance<IDBService>(); .... var data = dbService.GetObject(); .... } }
這裡只是一個小小的改動,DIContainer作為一個中介,通過它的接口GetInstance指定所需要的變元,這個變元具有抽象界面定義IDBService即可。DIContainer就像一個黑匣子,它知道如果根據要求的服務提供具體class的變元。這就是DI的典型應用例子。如果MyDataReader需要從不同的數據源取數據,將來MyDataReader根本不需要改動,只要告訴DIContainer即可。 這個服務元可能是從MyDbService,也可能是通過類似別的class如SqlDbService或OracleDbService。
現在有關DI的編程模式有許多,我個人認為,作為一個熟練的編程人員,應該學習和掌握這方面的知識,這樣就可以寫出更好、更乾淨、可維護和擴展的應用程序。在學習之前,首先要明白DI的道理,解決什麼類型的問題,這樣就容易理解DI的重要性和各種DI是如何解決這類問題的。如果你能熟練地運用DI技術,你的編程技術將會是高人一籌,而且如果你將來工作有這方面的要求,你將不會面對天書而一頭霧水。
本文為我試圖用萬維網博客寫技術方面(我在新浪博客上也做了成功的嘗試)的一個嘗試,萬維網博客提供有限的界面,但提供源代碼接口,這樣就可以直接通過HTML碼加入我所需要的基本功能。我今天寫了一篇英文博客,以此為藍本,我成功地復製成中文版的技術博文,編碼帶有不同的顏色,花的功夫不太大,這次嘗試看來是成功的。 |