[英]Why Use Interfaces Instead of Abstract Classes With DI?
我開始學習依賴注入的過程,其中一個原因是我看到為什么使用DI是一個好主意,它明確指定了你的依賴關系,這也使你的代碼更加清晰。
我也注意到接口被大量使用,但我想知道為什么我們不會僅僅為了指定默認構造函數而使用抽象類?
當然,抽象類中不能包含任何實現。
不會這樣:
abstract class FooBase
{
protected IBar _bar;
FooBase(IBar bar)
{
_bar = bar;
}
abstract void DoSomething();
abstract void DoSomethingElse();
}
更清楚地展示FooBase對象的依賴性超過:
interface IFoo
{
IBar Bar { get; }
void DoSomething();
void DoSomethingElse();
}
?
請記住,我是這個概念的新手,所以要好:)
一個技術原因 - 在沒有多重繼承的語言中強制使用特定父類(Java / C#)將極大地限制“接口”的實現自由。
請注意,“接口”字后面隱藏着兩個概念,這使得在C#中更難理解:
抽象/具體類可用於表示契約,但強制限制C#中的契約實現者。
其他一些語言(如C ++)沒有這樣的限制,抽象類是很好的選擇。 其他語言(即“duck-types”JavaScript)沒有這樣的類/接口區別,但您仍然可以與對象“契約”。
樣品:
為了提供更多應該在C#中實現此限制的上下文:DI通常與某種形式的TDD一起使用,或者至少與基本單元測試一起使用。 因此,您嘗試編寫一些使用DI的抽象基類的代碼和測試。
abstract class Duck {
abstract void Quack();
}
class ConcreteDuck : Duck {...}
現在,如果你決定編寫測試,你可能已經有了可以幫助你模擬對象的測試類(如果你沒有使用現有的一次)
class MockBase {...}
class MockDuck : MockBase,?????? // Can't use Duck and MockBase together...
接口定義了合同。 Abstract基類定義了一個行為。
從本質上講,您可以提供一個實現多個接口的類,然后可以將其注入多個類,但是您只有一個抽象基類(至少在C#中)。
考慮在容器上注冊類型的點(最好是組合根),並考慮解決依賴關系的點(構造函數或屬性)。
這個SO將涵蓋接口與基類的更多方面
在.NET中,您只有單繼承。 在這種情況下的語言/框架中,選擇使用抽象類作為抽象可以“燒掉基類” 。
這意味着您強制抽象的實現者從單個類繼承,強制它們這樣做可能會導致嚴重不便,具體取決於實現的內容。
假設您有抽象類Contract
。 如果某人有自己想要使用的Base
類,那么只暴露protected
方法(對於繼承者)。
因為這些方法是protected
,所以不能使用封裝(存儲在字段中的Base
實例)來訪問Base
用於抽象實現的方法。
更糟糕的是,如果您無權修改Base
,那么您可能不得不訴諸一些非常難看的變通方法(即反射,即)。
也就是說,通過接口,您可以為實現者選擇繼承的位置,而不是限制其選項。
您將看到的典型模式是,您始終為合同提供界面,並根據界面對您的消費者進行編碼。 您還提供了一個抽象基類,它提供了人們可能為了方便而從中派生的功能,但沒有義務從中派生 。
此外,如果您可以以易於封裝的形式提供此功能(對於我上面描述的條件),它將更加優化(您將擁有一個抽象類,它只調用暴露的實例)方法)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.