依賴注入是否值得?

梧桐雨—168發表於2008-03-26

  部落格的世界裡進行了一場關於使用依賴注入(DI)之優點和缺點的有趣討論。論題是:依賴注入是否真的值得?

  討論始自Jacob Proffitt,他撰文解釋他的觀點說,依賴注入的伸縮性不好。據Proffitt認為,DI流行的唯一原因是Mocking。

  DI進來這麼流行的真實原因,和正交性、封裝性或者其他“純粹的”架構考量都沒有關係。真正的原因是很多開發者都用DI來幫助使用Mock物件進行單元測試。隨你怎麼說,這個因素實際上說服了聰明的開發者選擇DI而不是更簡單的實現。

  Proffitt甚至聲稱DI只對單元測試有好處:

  不管怎樣,我真的希望人們能夠承認DI除了單元測試之外,沒什麼其他有說服力的應用。

  不過,Proffitt雖然做單元測試,卻不用DI。他使用TypeMock框架。這個框架可以攔截對依賴物件的呼叫,哪怕依賴是在被測試程式碼中建立的。這意味著Proffitt不用解耦他的物件也能為單元測試建立Mock。

  Ayende是RhinoMocks的創造者,他在自己的部落格上回應說:

  雖然能夠方便地編寫Mock程式碼是很棒的特性,但這只是主要利益之外的附帶好處,主要的利益是降低了物件間的耦合。我可以修改資料訪問部分的程式碼,而不需要觸及負責工資計算的引擎,這是我得到的主要益處。

  Nate Kohari也回答了Proffitt的原帖。Kohari不但給出了一個DI的程式碼示例,還詳細闡述了什麼是真正的DI:

  如果你是GoF的愛好者,這其實就是Strategy模式。依賴注入(按照我的觀點)本質上是大規模使用的Strategy模式。

  Kohari是NInject DI框架的作者,他強烈反對DI框架無用的說法:

  一旦你開始倚靠DI框架來編寫程式碼,連線物件所需的代價就下降到接近於零。於是,要想達到單一職責的目標,其難度會指數級地下降。

  在隨後的帖子中,Kohari重申了使用框架的重要性,以此來回應Proffitt原先認為DI的伸縮性不佳的說法:

  在真實世界的使用場景中,手工進行的依賴注入的確伸縮性不佳。

  Proffitt不同意:

  你怎麼能說依賴注入(我不是針對整個控制反轉模式,但也未嘗不可。只是還沒輪到。)創造了易於複用的鬆散耦合的單元?DI本身就要求呼叫者去提供被呼叫者的所需。任何理性的評價都會認為這是提高了耦合程度。把耦合的負擔丟給框架並不能改變事實,使用一個物件,仍然需要先給它提供外部的東西。

  Kohari解釋在大多數情況下,如何建立和注射特定型別的物件只需要配置一次,而且是由框架完成的,不是由呼叫者。

  Kohari還談到了程式碼的變化能力:

  ……簡單來說,依賴注入讓你的程式碼更容易改變。這就是它在敏捷社群中流行的原因,他們的整個軟體開發實踐都圍繞著快速變化。

  Eli Lopian是設計出TypeMock的公司的CTO也加入爭論,他對爭論的核心有不同的看法:

  當你把DI當作是“銀彈”來使用,你就喪失了所用程式語言的一大半能力。你不能用靜態方法,不能用“new”關鍵字,不能用封閉型別。哦,你還要把所有的方法都變成虛擬的。

  他還爭辯說,僅僅為了方便變化而使用DI,違背了YAGNI原則。

  Lopian繼續說:

  TDD剛興起時,首先被討論的一個問題就是“我們是否應該修改程式碼來滿足可測試的要求?”我們應不應該改變程式碼的可見性?我們應不應該改變程式碼的設計?這個問題導致了可測試的程式碼與OO封裝性之間的衝突。開發者們開始為了能夠測試,而把程式碼中的私有部分暴露出來。開頭只是私有方法和屬性,現在擴大到了整個設計。

  這是一個老問題了。有些人認為改變程式碼讓它更容易測試是一件好事;其他人認為這樣做打破了封裝性,因此是壞事。

  Kohari對封裝與依賴的的關係提出了看法:

  這是讓依賴注入物有所值的祕密:當談到依賴的時候,封裝是壞的。

  如果出於單元測試的意圖而改變程式碼,能讓耦合變得更鬆散(Proffitt對此有所質疑)——這是不是一件好事呢?

  鬆散耦合與封裝都是重要的OO特徵,那我們如何作出平衡呢?哪條路才是對的?

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/13270562/viewspace-217886/,如需轉載,請註明出處,否則將追究法律責任。

相關文章