2011-10-06 107 views
3

我理解依賴注入,但沒有那個「啊」的時刻,點擊它,我真的看到了光。嘲笑的問題和依賴注入

我爲什麼要用DI?另外,當嘲諷那些使用文件系統的對象時,模擬對象能夠做什麼?它只是做虛擬調用(所以不真的使用文件系統)?

回答

1

讓我去一對夫婦從hvgotcodesanswer幾步遠:

class Service { 
    Collaborator c = new Collaborator() 
} 

是你原來的班用硬編碼的依賴性。

class Service { 
    Collaborator c; 

    Service(Collaborator c) { 
     this.c = c; 
    } 
} 

是你的注入依賴的新類。

到目前爲止,這麼好。現在,讓我們取Collaborator並從中提取一個接口;稱它爲ICollaborator。現在你的新玩家看起來像這樣:

class Service { 
    ICollaborator c; 

    Service(ICollaborator c) { 
     this.c = c; 
    } 
} 

這是什麼給你買的?那麼,你可以在你的代碼,創建該類的行爲像第一個例子是這樣的:

// w00t! My code compiles and works again! Ship it! 
Service myService = new Service(new Collaborator()); 

漂亮添油加醋容易。當你想要使用不同類型的Collaborator時,美麗來自於 - 也許甚至是模擬或假的。只要它實現了接口ICollaborator,你就是金:

// I'm using Fake It Easy for this example. 
Service myService = new Service(A.Fake<ICollaborator>()); 

瞧!你現在有一個單元可測試的Service實例,它不會拖拽混凝土Collaborator(這將打破真正的「單元」測試)。

+0

我明白了。我明白,這是一個類似日期時間的好處。如果datetime從一個接口派生,並且我從同一個接口創建另一個類,那麼這些方法可以是空的存根嗎? – dotnetdev

+0

準確!現在,任何具有返回類型的方法都應該爲該方法返回合理的值,但void方法可以是完全空的存根。 –

1

依賴注入只是一種不硬編碼依賴到組件的做法。例如,

class Service { 
    Collaborator c = new Collaborator() 
} 

該僞碼具有合作者硬編碼。這很難改變。如果你沒有

class Service { 
    Collaborator c; 

    Service(Collaborator c) { 
     this.c = c; 
    } 
} 

現在你可以通過構造函數'注入'所需的協作者到服務組件中。沒有硬編碼的依賴關係。

這很好,您可以輕鬆地更換協作者的實現。您的代碼現在「鬆散耦合」 - 對特定實現沒有硬性依賴關係,僅限於類型和行爲。

這樣做的一個應用是,您現在可以在測試中注入一個模擬協作器來測試Service,這樣您就可以以不依賴協作者的方式測試所有服務功能。

實際上,您希望Collaborator成爲一個接口(或任何與您的選擇語言支持相當的接口),以便您可以定義行爲並將實現留給您注入的實際實例。

問題的第二部分,關於嘲笑執行文件操作的協作者是正確的。如果您嘲笑文件系統協作者,則可以單獨測試使用協作者而不實際擊中文件系統的內容

2

DI的目的是使代碼鬆散耦合。根據定義,鬆散耦合需要單元測試,因爲如果許多類緊密耦合,它不再是單元測試(而是集成測試)。

但是,DI的目的不是爲了啓用單元測試,而是爲了讓您的代碼庫更易於維護。許多積極的副作用之一是它也變得非常可測試。

當談到嘲諷文件系統,它基本上是一個壞主意,文件系統等方面過於緊密鏡子,因爲這將導致Leaky Abstraction。相反,你應該考慮使用流或類似的概念。

0

要添加更多的討論......

很多時候人們談論DI的主要論點將沿着可測性的線條,但正如馬克·西曼指出的(順便說一下買他的書的時候關於DI,非常有啓發性,對廣告抱歉)最重要的方面是讓你的應用程序鬆耦合,因此更易於維護。

要提供一個例子,在其他的答案中相同的代碼:

比方說,你得到的是,根據新的要求....我不知道....一年的時間,你需要使用不同的合作者,你可以這樣做以下:

ICollaborator collaborator; 

switch(timeOfYear) 
{ 
    case "Spring": 
     collaborator = new SpringCollaborator(); 
     break; 
    case "Summer": 
     collaborator = new SummerCollaborator(); 
     break; 
    case "Fall": 
     collaborator = new FallCollaborator(); 
     break; 
    case "Winter": 
     collaborator = new WinterCollaborator(); 
     break; 
} 

Service myService = new Service(collaborator); 

這種方式,因爲你需要和你的服務將永遠不需要改變,因爲它不關心你可以創建許多實現只要它實現ICollaborator接口,協作者的詳細信息。

有很多關於DI的更多信息,但鬆耦合和可測性始終是首先指出的兩個好處。

問候。