2012-03-07 14 views
12

In generale, l'interfaccia o la classe astratta è spesso la decisione appropriata, giusto?Il tipo di ritorno di una dichiarazione del metodo deve essere interfaccia o classe concreta?

Ma in alcuni casi, sembra che la classe concreta è meglio. Per esempio,

public string Replace(string old, string new) 

Il metodo di StringReplace restituisce una classe concreta. (E 'solo un esempio, anche se String non implementa alcuna interfaccia.)

La mia domanda è

  1. Quando devo restituire un interfaccia, e quando devo tornare una classe concreta?

  2. E 'una parte del program to an interface, not an implementation per la restituzione di un'interfaccia?

risposta

4

Dipende.

Ho visto questa domanda ha chiesto un paio di volte, ed ecco un bel esempio per illustrare il "dipende" risposta.

Si consideri la seguente classe:

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 restituisce un IEnumerable e Test2 restituisce una concreta attuazione dell'interfaccia IEnumerable (List in quel caso). Qual è il metodo migliore? Test o Test2?

In realtà, entrambi sono semanticamente differenti:

  • Come Test restituisce solo un IEnumerable, è implica che si tratta di una parte del contratto metodo di che lo sviluppatore utilizza l'oggetto restituito in un'enumerazione (foreach).
  • As Test2 restituisce un'istanza List, consente all'utente di accedere agli oggetti dello List per indice. È un utilizzo completamente diverso dell'oggetto restituito.

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

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

    Console.ReadKey(); 
} 

Se vi aspettate che lo sviluppatore utilizzare l'oggetto restituito in un'enumerazione solo, allora si potrebbe utilizzare l'interfaccia come tipo di ritorno. Se si prevede che lo sviluppatore utilizzi metodi/proprietà dell'implementazione concreta dell'interfaccia (nell'esempio precedente, accesso all'oggetto per indice), è possibile restituire un tipo concreto.

Ricorda anche che a volte non hai scelta. Ad esempio, se si desidera esporre una raccolta pubblica da utilizzare per un binding Silverlight, è necessario restituire ObservableCollection<T>, non IEnumerable<T>, poiché il sistema di associazione richiede effettivamente il metodo/proprietà/comportamento della classe ObservableCollection (IEnumerable non sarà sufficiente per il legame di lavoro).

Quello che dovresti evitare è un metodo che restituisce IEnumerable<T> e che viene utilizzato ogni volta con ToList().

+0

Odio i metodi che restituiscono IEnumerable quando tutto ciò che otteniamo è un elenco . Non riesco a utilizzare un ciclo for regolare (elemento di riferimento con il suo indice) o anche a chiamare il metodo Count più semplice (senza utilizzare il metodo LINQ Count). Quando tutto ciò che faccio è restituire una lista, il tipo di ritorno che uso è IList . I/I principalmente restituire IEnumerable quando utilizzato in combinazione con un rendimento restituito. Un sidenote: quando si sviluppa una libreria pubblica, l'utilizzo di un oggetto IEnumerable potrebbe tuttavia avere più vantaggi. – Nullius

1

Si sta ottenendo il Program to an interface, not an implementation sbagliato credo. Ciò che il GOF intende per programma per un'interfaccia, è l'interfaccia del tipo.

Definiscono l'interfaccia di un oggetto come tutti i metodi visibili dall'esterno. Quindi la loro definizione di interfaccia in questo caso è diversa da quella che hai in C# per esempio.

Per quanto riguarda la tua domanda, credo che sia probabilmente meglio restituire la classe astratta. Funzionerà se restituisci qualsiasi oggetto derivato da quella classe astratta? Se sì, restituisci la classe astratta. In caso contrario, vai più specifico e restituisci un tipo derivato.

+0

Per ulteriori informazioni sul programma "Programma per un inferface", dai un'occhiata alla sua intervista con Erich Gamme: http://www.artima.com/lejava/articles/designprinciples.html – sloth

+0

@squelos Non intendo 'Programmare su un'interfaccia' è solo restituire un'interfaccia per un metodo. Intendo quando la tua API restituisce un'interfaccia, l'utente che usa la tua API potrebbe fare 'Programmazione su un'interfaccia'. Se si restituisce una classe concreta, non è possibile forzare l'utente a utilizzare l'interfaccia. –

+0

Oh ok, mi ero sbagliato allora. Avevo qualche dubbio su ciò che intendevi per "interfaccia", quindi ho preferito chiarire. Nessun problema quindi – squelos

3

Secondo me dipende, ad esempio, se si dispone di un metodo che viene utilizzato in modo strettamente accoppiato, ad esempio Classe 1 chiama il metodo A in Classe 2 e vuole sempre un determinato tipo ed è l'unica volta che viene chiamato il metodo allora potresti obiettare che non ha senso Un esempio di ciò potrebbe essere restituire IEnumerable, in cui il metodo crea la raccolta come un elenco, quindi lo restituisce come IEnumerable, la classe 1 quindi la consuma come elenco in ogni caso in modo che il ritorno abbia bisogno di ToList() per essere richiamato comunque.

Tuttavia, quando sto scrivendo un'interfaccia più disaccoppiata tra classi come un livello dati, preferisco sempre restituire il denomnatore comune più basso (ad esempio IEnumarable) e consentire al consumatore di non avere alcuna conoscenza su cosa decidere fare con esso.

0

A seconda di quanto accesso si desidera dare all'utente del codice!

Voglio dire, restituire List<AccountStatement> a un utente non ha alcun senso. Perché, non ti piacerebbe che l'utente del tuo codice AGGIUNGI una nuova dichiarazione in questa raccolta (una dichiarazione dovrebbe essere creata al momento della prenotazione di una particolare transazione)

Quindi, in questo caso puoi solo restituire IEnumerable<AccountStatement> - solo accesso in lettura.

In generale, faccio sostenere l'idea di tornare Interfacce da metodi per le seguenti ragioni:

  • Si ottiene un migliore controllo di accesso si dà per il tuo oggetto al mondo esterno.
  • si arriva a nascondere i dettagli di implementazione (per questo esempio, anche la vostra classe può rimanere interna per il montaggio)
  • E 'in linea con l'interfaccia segregazione Principio (esporre solo il comportamento che si desidera con il ritorno, e l'attuazione di , l'interfaccia giusta).

A proposito, il tuo esempio di restituzione di "stringa" non è molto utile. È un tipo di dati primitivo (intendo un tipo di dati nativo in mscorlib) e non c'è molto da nascondere/mostrare in questo oggetto.

+0

erm ... le stringhe non sono un tipo primitivo. – Sinaesthetic

+0

Aggiunta di una correzione aggiunta. Intendevo che si tratta di un tipo di dati comunemente usato nativo. –

Problemi correlati