2012-03-07 102 views
12

在一般情況下,界面或抽象類往往是適當的決定,我是對嗎?方法聲明的返回類型應該是接口還是具體類?

但在某些情況下,它看起來像具體的類更好。例如,

public string Replace(string old, string new) 

String的的Replace方法返回的具體類。 (這只是一個例子,儘管字符串沒有實現任何接口。)

我的問題是

  1. 當我應該返回一個接口,當我應該返回的具體類?

  2. 是否返回界面program to an interface, not an implementation的一部分?

回答

4

這取決於。

我已經看到了這個問題問了幾次,這裏是一個很好的例子,來說明「這取決於」的答案。

考慮下面的類:

public class MyClass 
{ 
    public static IEnumerable<int> Test() 
    { 
     return new List<int> { 2, 3, 4 }; 
    } 

    public static List<int> Test2() 
    { 
     return new List<int> { 2, 3, 4 }; 
    } 
} 

Test返回IEnumerableTest2返回一個具體實現IEnumerable接口(List在這種情況下)的。什麼是最好的方法? TestTest2

事實上,無論是在語義上是不同的:

  • 作爲Test只返回一個IEnumerable,它意味着,它的合同的方法,開發人員使用返回的對象枚舉的一部分(foreach )。
  • 由於Test2返回List實例,它允許用戶通過索引訪問List的對象。這與返回的對象完全不同。

private static void Main(string[] args) 
{ 
    foreach (var z in MyClass.Test()) 
    { 
     Console.WriteLine(z); 
    } 

    var f = MyClass.Test2()[0]; 

    Console.ReadKey(); 
} 

如果你希望開發者使用返回的對象枚舉只,那麼你可以使用接口作爲返回類型。如果你希望開發者使用方法/具體實施的接口的屬性(在上面的例子中,訪問由索引對象),那麼你可以返回一個具體類型。

還記得,有時候你別無選擇。例如,如果要公開應當用於爲Silverlight結合公開徵集,那麼你就應該返回ObservableCollection<T>,不IEnumerable<T>,因爲結合系統實際需要ObservableCollection類的方法/屬性/行爲(IEnumerable會不會足以讓綁定工作)。

你應該避免的是一種方法,返回IEnumerable<T>並且每次與ToList()一起使用。

+0

我討厭那些返回IEnumerable 的方法,當我們得到的是一個List 。我不能使用常規for循環(參考項與其索引),或者甚至調用最簡單的Count方法(不使用LINQ Count方法)。當我所做的只是返回一個列表時,我使用的返回類型是IList 。與收益回報結合使用時,我只/大部分會返回IEnumerable 。一個註釋:在開發公共圖書館時,使用IEnumerable可能會有更多優勢。 – Nullius 2015-11-02 13:23:46

1

您正在收到Program to an interface, not an implementation錯誤,我相信。 GOF的意思是程序對接口的意義是類型的接口。

它們將對象的接口定義爲從外部可見的所有方法。因此,在這種情況下,它們的接口定義與您在C#中的定義不同。

關於你的問題,我會認爲返回抽象類可能會更好。如果您返回從該抽象類派生的任何對象,它會起作用嗎?如果是,則返回抽象類。 如果不是,則更具體,並返回派生類型。

+0

有關「計劃到inferface'設計princible更多信息,看看他的專訪埃裏希的Gamme:http://www.artima.com/lejava/articles/designprinciples。html – sloth 2012-03-07 09:19:08

+0

@squelos我不是指'編程接口'只是返回一個方法的接口。我的意思是當你的API返回一個接口時,使用你的API的用戶可以做'編程到接口'。如果你返回一個具體的類,你不能'強迫'你的用戶使用接口。 – 2012-03-08 02:18:57

+0

噢,我錯了。我對「界面」所理解的內容有所懷疑,所以我首選澄清。沒問題,然後 – squelos 2012-03-08 08:06:01

3

在我看來,這取決於說,如果你有在緊密耦合方式使用的方法,對2級,即1所調用方法A和總是想某種類型並調用該方法,那麼唯一的一次你可以爭辯說沒有意義。這方面的一個例子可以返回IEnumerable的,該方法創建集合爲一個列表,然後返回它爲IEnumerable,1級,然後消耗,作爲一個列表反正這樣的回報都要ToList()被在其反正叫。

然而,當我在諸如數據層之類的類之間寫入一個更加分離的接口時,我總是更願意返回最低的通用denomnator(例如IEnumarable),並允許我可能不知道的消費者決定什麼用它做。

0

取決於你想要多少訪問給你的代碼的用戶!

我的意思是,返回List<AccountStatement>用戶將沒有任何意義。因爲,您不希望您的代碼的用戶在此集合中添加新語句(在預訂特定事務時應創建一條語句)

因此,在這種情況下,您可能只返回IEnumerable<AccountStatement> - 只讀訪問。

一般來說,我支持恢復從方法接口的理由如下的想法:

  • 您在訪問得到較好的控制,你給你的對象到外面的世界。
  • 你到隱藏實施細則(適用於例如,即使你的類可以保持內部組裝)
  • 它是在線與接口分離原則(僅暴露希望通過返回的行爲,並實施,正確的界面)。

順便說一句,你返回「字符串」的例子沒有多大用處。它是一種原始數據類型(我的意思是mscorlib中的一種本地數據類型),並且在這個對象中隱藏/顯示的內容並不多。

+0

erm ...字符串不是原始類型。 – Sinaesthetic 2012-07-06 04:06:58

+0

添加更正聲明。我的意思是它是一種本地常用數據類型。 – 2012-07-10 04:00:12

相關問題