.NET Core TDD 前傳: 編寫易於測試的代碼 -- 依賴項

第1篇: 講述了如何創造"縫".  "縫"(seam)是須要知道的概念.html

第2篇, 避免在構建對象時寫出不易測試的代碼.函數

本文是第3篇, 講述依賴項和迪米特法則.測試

 

迪米特法則 (Law of Demeter)

仍是使用建造汽車的例子. 生產汽車的時候須要輪胎, 組裝時須要什麼型號的輪胎, 就請求該型號的輪胎, 而後相關人員會從庫房把該型號的輪胎送到產線用於組裝. spa

我相信不多有汽車廠會這樣作: 生產汽車時, 汽車組裝工拿着庫房的鑰匙, 本身去庫房從各類各樣的輪胎中找所須要的型號..htm

這就是違反迪米特法則的一個例子.對象

 

迪米特法則大概的意思是: "只訪問你本身建立的對象, 或者做爲參數傳給你的對象. 不要經過其它對象間接的訪問對象"blog

用一句話概括迪米特法則就是: "只與直系朋友交談, 不要和陌生人交談".接口

 

注意: 迪米特法則其實並不算嚴格的法則, 它只是一個很是有益的指導性原則. get

 

存在的問題

用代碼形容上面的例子就是: 容器

這違反了迪米特法則, 致使瞭如下問題:

  • 形成了BenzCar和Warehouse以及MichelinTire之間的緊耦合, 而實際上BenzCar只須要MichelinTire.
  • 測試時, 設置會很麻煩. 代碼裏Warehouse是直系朋友, MichelinTire是陌生人. 咱們須要爲Warehouse和MichelinTire同時設置測試替身.
  • 真正須要的依賴項沒有明確在構造函數裏定義. 這裏Warehouse至關因而一個容器, 測試時, 咱們可能會不知道要爲Warehouse裏的哪一個東西作測試替身.

 

危險信號

下列寫法可能意味着您的代碼違反了迪米特法則:

  • 代碼裏有這樣的調用: "warehouse.getTire.getMichelinTire", 有一連串的點".". 可是有時候這樣作是能夠的, 例如流暢(fluent)形式的建造者模式就能夠, 由於fluent接口一般會返回對象自己, 而後再去使用該對象.
  • 依賴於容器. 例如把 IocContainer做爲依賴注入使用. 
  • 依賴項的名稱爲XxxContext, XxxContainer, XxxEnvironment, XxxManager, XxxServiceLocator.
  • 測試時須要建立返回mocks的mock對象.
  • 測試時的設置很是麻煩.

 

解決辦法

解決辦法就是聽從迪米特法則.

只注入咱們直接須要的依賴項, 直接使用它們. 這樣就會保證依賴項很明確, 測試的時候一眼就能看出依賴於哪些對象.

代碼示例

例子一

下面這個違反了迪米特法則, 直接注入的是Warehouse, 而實際用到的倒是MichelinTire:

 

正確的作法是, 注入直接使用的依賴項:

 

例子二

下面的代碼也違反了迪米特法則, 它注入了一個容器類的對象:

這個ServiceLocator就至關因而一個容器. 這樣用的話, 寫測試的人可能根本沒法知道須要使用容器裏面的哪一個對象.

你也許會說這樣作靈活(我之前也常常這樣作), 可是重構的時候, 這裏很容易出錯, 由於根本看不出來真正依賴的是哪一個對象.

 

正確的作法仍是應該注入直接須要的依賴項:

 

Law of Demeter相關的內容就簡單介紹這些.

相關文章
相關標籤/搜索