依賴注入是否值得?
部落格的世界裡進行了一場關於使用依賴注入(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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- angular依賴注入Angular依賴注入
- XUnit 依賴注入依賴注入
- Struts 依賴注入依賴注入
- 依賴倒置(DIP)與依賴注入(DI)依賴注入
- 依賴注入?依賴注入是如何實現解耦的?依賴注入解耦
- ASP.NET Core中的依賴注入(2):依賴注入(DI)ASP.NET依賴注入
- [譯] 依賴注入?? 哈??依賴注入
- Angular 依賴注入原理Angular依賴注入
- .Net Core — 依賴注入依賴注入
- 理解 Angular 依賴注入Angular依賴注入
- Spring依賴注入Spring依賴注入
- Spring依賴注入---Spring依賴注入
- 依賴注入系列教程依賴注入
- 我看依賴注入依賴注入
- webapi - 使用依賴注入WebAPI依賴注入
- Asp .Net Core 依賴注入依賴注入
- Spring IOC——依賴注入Spring依賴注入
- 入門系列-依賴注入依賴注入
- C# 依賴注入 & MEFC#依賴注入
- Spring 依賴注入 DISpring依賴注入
- 關於依賴注入(typescript)依賴注入TypeScript
- 什麼是依賴注入依賴注入
- .NET8 依賴注入依賴注入
- spring 的依賴注入Spring依賴注入
- 深入淺出依賴注入依賴注入
- C# Unity依賴注入C#Unity依賴注入
- JavaScript裡的依賴注入JavaScript依賴注入
- 依賴注入那些事兒依賴注入
- iOS實現依賴注入iOS依賴注入
- Guice指南-手工依賴注入GUI依賴注入
- Sping-依賴注入依賴注入
- IOC容器和依賴注入依賴注入
- Golang 依賴注入設計哲學|12.6K 🌟 的依賴注入庫 wireGolang依賴注入
- Spring系列.依賴注入配置Spring依賴注入
- Laravel 使用依賴注入呼叫方法Laravel依賴注入
- 類的反射和依賴注入反射依賴注入
- Spring.Net 依賴注入Spring依賴注入
- .NET之預設依賴注入依賴注入