[英]Interfaces as parameters
在什么情況下有人會將接口作為參數傳遞(或接收)? 這真的是一件有用的事情還是一種奇特的做事方式?
這是一個非常有用的東西。
例如,采用任何 LINQ擴展方法 。 他們不關心傳遞給他們的是什么,只要它實現IEnumerable<T>
。 我們的想法是,它們都可以應用於使用foreach
循環可以枚舉的任何內容。
想象一下,如果他們都要求你傳遞T[]
數組或List<T>
對象,那將是多么無意義的限制。
這只是一個非常簡單的例子。 讓我們假裝LINQ擴展不存在(如果我使用的是.NET 2.0,這實際上是一種可能性)並且我想編寫一個Sum
方法。
我可以像這樣寫:
public static double Sum(List<double> values)
{
double sum = 0.0;
foreach (double value in values)
{
sum += value;
}
return sum;
}
這一切都很好,但在這里注意一些事情:我編寫了一個方法來獲取List<double>
,這是一個具有比這個代碼所依賴的更多功能的類。 它在哪里使用Insert
? 它在哪里使用RemoveAt
? FindAll
? Sort
? 不,這不是必需的。 那么這個方法真的有必要通過List<double>
嗎?
而且,說我有double[]
。 從理論上講,我應該能夠將其作為values
參數彈出,因為我所做的就是使用foreach
枚舉它; 但由於我輸入的values
List<double>
,要將double[]
傳遞給我的Sum
方法,我必須這樣做:
double sum = Sum(new List<double>(myArray));
這只是一個完全不必要的新對象,我構建它只是為了調用真正應該能夠首先處理我的原始對象的代碼。
通過編寫將接口作為參數的方法,您可以使代碼更靈活,更強大,並且您可以避免在調用代碼時施加不適當的限制( 給我一個X,即使我可以很容易地使用Y )。
最簡單的方法是,它是關於編程接口而不是實現。 比方說,我有一個方法,我想做某事,例如
public void MakeNoise(IAnimal animal)
{
animal.MakeNoise();
}
我不在乎具體實現是什么,我只知道無論傳入什么,我都可以調用MakeNoise()。 我編程到一個接口,而不是一個實現。
public class Dog : IAnimal
{
public void MakeNoise()
{
Console.WriteLine("Woof");
}
}
public class Cat : IAnimal
{
public void MakeNoise()
{
Console.WriteLine("Meow");
}
}
接口編程是OOP的核心方面,你會發現它們非常有用。
每當你需要抽象時。
一個很好的例子是.NET Framework中的IEnumerable<T>
和IQueryable<T>
接口。 它們允許您編寫可用於List<T
>, Dictionary<TKey, TValue>
甚至T[]
擴展方法。
例如,您也可以使用依賴注入。 在ASP.NET MVC中,通常使用存儲庫進行數據訪問:
public class MyClassRepository
{
public MyClass GetById(int id)
{
// Some Implementation
}
}
public class MyController
{
private MyClassRepository _repo;
public class MyController() : base(new MyClassRepository()) { }
public class MyController(MyClassRepository repo) { _repo = repo; }
}
現在,如果你想模擬用於單元測試的存儲庫...你就是骨頭。 沒有簡單的方法。 接口來了!
public interface IMyClassRepository
{
public MyClass GetById(int id);
}
public class MyClassRepository : IMyClassRepository
{
public MyClass GetById(int id)
{
// Some Implementation
}
}
public class MyController
{
private IMyClassRepository _repo;
public class MyController() : base(new MyClassRepository()) { }
public class MyController(IMyClassRepository repo) { _repo = repo; }
}
現在通過引入接口,我們可以自由地模擬IMyClassRepository但是我們認為適合於測試目的。 通常,這涉及一個具有指定行為的簡單模擬對象,以產生可靠的結果
接口非常有用。
它們有助於解耦代碼 - 例如,如果使用IList
接口並將其傳遞給方法並在方法中使用它,則可以傳入實現此接口的任何集合,無論它是否在BCL中。
多態性!
它們可以幫助您編寫不歧視某些類的代碼,因為它們不會從特殊的基類繼承。 您的職能將是平等機會執行者。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.