2012-03-07 17 views
12

En el escenario general, la interfaz o clase de resumen suele ser la decisión adecuada, ¿estoy en lo cierto?¿El tipo de devolución de una declaración de método debe ser de interfaz o clase concreta?

Pero en algunos casos, parece que la clase de hormigón es mejor. Por ejemplo,

public string Replace(string old, string new) 

El método de StringReplace devuelve una clase concreta. (Es sólo un ejemplo, aunque cadena no implementa las interfaces.)

Mi pregunta es

  1. Cuando debería devolver una interfaz, y cuando debería devolver una clase concreta?

  2. ¿Es parte de program to an interface, not an implementation devolver una interfaz?

Respuesta

4

Depende.

He visto esta pregunta un par de veces, y aquí hay un buen ejemplo para ilustrar la respuesta "depende".

Considérese la siguiente clase:

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 devuelve un IEnumerable y Test2 devuelve una aplicación concreta de la interfaz IEnumerable (List en ese caso). ¿Cuál es el mejor método? Test o Test2?

En realidad, ambos son semánticamente diferente:

  • Como Test sólo se devuelve un IEnumerable, que implica que es una parte del contrato método que el desarrollador utiliza el objeto devuelto en una enumeración (foreach)
  • Como Test2 devuelve una instancia de List, que permite al usuario acceder a los objetos del List por índice. Es una utilización totalmente diferente del objeto devuelto.

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

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

    Console.ReadKey(); 
} 

Si usted espera que el desarrollador para utilizar el objeto devuelto en una enumeración solamente, entonces se podría utilizar la interfaz como tipo de retorno. Si espera que el desarrollador use métodos/propiedades de la implementación concreta de la interfaz (en el ejemplo anterior, acceso al objeto por índice), puede devolver un tipo concreto.

También recuerde que a veces no tiene otra opción. Por ejemplo, si desea exponer una colección pública que debe usarse para un enlace de Silverlight, debe devolver ObservableCollection<T>, no IEnumerable<T>, porque el sistema de enlace realmente necesita el método/propiedades/comportamiento de la clase ObservableCollection (IEnumerable no sería suficiente para que el enlace funcione).

Lo que debe evitar es un método que devuelve IEnumerable<T> y que se usa con ToList() cada vez.

+0

Odio los métodos que devuelven IEnumerable cuando todo lo que obtenemos es una lista . No puedo usar un bucle for (elemento de referencia con su índice) o incluso invocar el método Count más simple (sin usar el método LINQ Count). Cuando todo lo que hago es devolver una lista, el tipo de devolución que uso es IList . Solo/principalmente devuelvo IEnumerable cuando se utiliza en combinación con un retorno de rendimiento. Una nota al margen: cuando se desarrolla una biblioteca pública, el uso de un IEnumerable podría tener más ventajas. – Nullius

1

Usted está recibiendo el Program to an interface, not an implementation mal, creo. Lo que significa GOF por programa para una interfaz, es la interfaz del tipo.

Define la interfaz de un objeto como todos los métodos que son visibles desde el exterior. Entonces, su definición de interfaz en este caso es diferente de la que tiene en C#, por ejemplo.

En relación con su pregunta, creo que es mejor devolver la clase abstracta. ¿Funcionará si devuelves cualquier objeto derivado de esa clase abstracta? Si es así, devuelve la clase abstracta. De lo contrario, vaya más específico y devuelva un tipo derivado.

+0

Para obtener más información sobre el principio del diseño de "Programa a una inferface", consulte su entrevista con Erich Gamme: http://www.artima.com/lejava/articles/designprinciples.html – sloth

+0

@squelos No me refiero a 'Programming to an interface' es solo devolver una interfaz para un método. Me refiero a que cuando tu API devuelve una interfaz, el usuario que usa tu API podría hacer 'Programming to a interface'. Si devuelve una clase concreta, no puede "forzar" a su usuario a usar la interfaz. –

+0

Oh ok, me equivoqué entonces. Tenía algunas dudas sobre lo que entendía por "interfaz", así que preferí aclararlo. No hay problema, entonces – squelos

3

En mi opinión, depende, digamos, si tiene un método que se usa estrechamente acoplado, es decir, la Clase 1 llama al Método A en la Clase 2 y siempre quiere un tipo determinado y es el único momento en que se llama usted podría argumentar que no tiene sentido. Un ejemplo de esto podría ser devolver IEnumerable, donde el método crea la colección como una lista, luego la devuelve como IEnumerable, Class 1 luego la consume como una lista de todos modos, por lo que la devolución necesitaría llamar a ToList() de todos modos.

Sin embargo, cuando estoy escribiendo una interfaz más desacoplada entre clases como una capa de datos, siempre prefiero devolver el mínimo común denominador (IEnumarable por ejemplo) y permitir que el consumidor que no tengo conocimiento decida qué hacer con eso.

0

Depende de cuánto tiene acceso que desea dar al usuario de su código!

Es decir, devolver List<AccountStatement> a un usuario no tendrá ningún sentido. Porque no le gustaría que el usuario de su código AGREGUE una nueva declaración en esta colección (se debe crear una declaración al reservar una transacción en particular)

Por lo tanto, en este caso puede devolver IEnumerable<AccountStatement> - solo acceso de lectura.

En general, hago apoyar la idea de volver Interfaces de métodos para la siguientes razones:

  • Se obtiene un mejor control de acceso que da a su objeto al mundo exterior.
  • se llega a ocultar los detalles de implementación (para esa instancia, incluso su clase puede permanecer interno de montaje)
  • Está en línea con la interfaz Segregación Principio (sólo exponer el comportamiento que desea mediante la devolución, y la implementación , la interfaz correcta).

Por cierto, su ejemplo de devolver "cadena" no es de mucha utilidad. Es un tipo de datos primitivo (me refiero a un tipo de datos nativo en mscorlib), y no hay mucho que ocultar/mostrar en este objeto.

+0

erm ... las cadenas no son de tipo primitivo. – Sinaesthetic

+0

Estado de corrección agregado. Quise decir que es un tipo de datos de uso común nativo. –

Cuestiones relacionadas