¿Es un mal hábito no usar interfaces? [cerrado]

40

Raramente uso interfaces y las encuentro comunes en otros códigos.

También creo subclases y superclases (mientras creo mis propias clases) rara vez en mi código.

  • ¿Es algo malo?
  • ¿Sugerirías cambiar este estilo?
  • ¿Este estilo tiene algún efecto secundario?
  • ¿Es esto porque no he trabajado en proyectos grandes?
jineesh joseph
fuente
10
¿Que idioma es este?
2
Además de qué lenguaje, ¿qué paradigma es este?
Armando
1
¿El concepto de "interfaz" no trasciende el lenguaje? Java tiene el tipo de interfaz incorporado, pero los desarrolladores de C ++ a menudo también crean interfaces (con el prefijo I) y todos tienen el mismo propósito.
Ricket
44
@Ricket: No, en realidad no. El problema es que C ++ ofrece herencia de clases múltiples. En C ++, una "interfaz" es mucho más conceptual y, en realidad, utilizamos principalmente lo que definirían como una clase base abstracta. #
DeadMG
2
@Ricket no, especialmente si está trabajando en un lenguaje funcional en lugar de uno de procedimiento o POO.
alternativa

Respuestas:

36

Hay varias razones por las que es posible que desee utilizar interfaces:

  1. Las interfaces son adecuadas para situaciones en las que sus aplicaciones requieren muchos tipos de objetos posiblemente no relacionados para proporcionar cierta funcionalidad.
  2. Las interfaces son más flexibles que las clases base porque puede definir una única implementación que puede implementar múltiples interfaces.
  3. Las interfaces son mejores en situaciones en las que no necesita heredar la implementación de una clase base.
  4. Las interfaces son útiles en los casos en que no se puede usar la herencia de clases. Por ejemplo, las estructuras no pueden heredar de las clases, pero pueden implementar interfaces.

http://msdn.microsoft.com/en-us/library/3b5b8ezk(v=vs.80).aspx

Las interfaces son como cualquier otra cosa en la programación. Si no los necesita, no los use. Los he visto utilizados ampliamente como una cuestión de estilo, pero si no necesita las propiedades y capacidades especiales que proporciona una interfaz, no veo el beneficio de usarlos "solo porque".

Robert Harvey
fuente
13
Su lenguaje no está especificado, y el tuyo es demasiado específico; por ejemplo, en C ++, una estructura puede heredar de una clase, y puedes multiplicar heredar bases no abstractas.
DeadMG
2
Esta respuesta parece ser C #, pero también pertenece a Java si saca # 4, y solo se aplica a C ++ porque, por supuesto, se permite la herencia múltiple en C ++.
Ricket
2
Además, no estoy de acuerdo con la última declaración. Creo que hay muchas buenas prácticas que los programadores deberían hacer pero no porque sienten que no las necesitan. Creo que el autor de la pregunta es muy sabio al mirar a su alrededor, ver a todos los demás haciendo esto y pensar que tal vez debería hacerlo también, pero preguntando "por qué" primero.
Ricket
3
@Ricket: El por qué está en los cuatro puntos de mi respuesta. Si ninguna de esas razones se aplica, entonces no necesita una interfaz.
Robert Harvey
17

Tanto la herencia de clase como las interfaces tienen su lugar. Herencia significa "es un", mientras que una interfaz proporciona un contrato que define cómo se comporta "algo".

Yo diría que usar interfaces con más frecuencia no es una mala práctica en absoluto. Actualmente estoy leyendo "Efectivo C # - 50 formas específicas para mejorar su C #" por Bill Wagner. El artículo número 22 establece, y una cita, "Prefiero definir e implementar interfaces a la herencia".

En general, uso clases base cuando necesito definir una implementación específica de comportamiento común entre tipos relacionados conceptualmente. Más a menudo uso interfaces. De hecho, normalmente empiezo definiendo una interfaz para una clase cuando empiezo a crear una ... incluso si al final no compilo la interfaz, encuentro que ayuda comenzar definiendo la API pública de la clase clase desde el principio. Si descubro que tengo varias clases implementando la interfaz, y la lógica de implementación es idéntica, solo entonces me preguntaré si tendría sentido implementar una clase base común entre los tipos.

Un par de citas del libro de Bill Wagners ...

todas las clases derivadas incorporan inmediatamente ese comportamiento. Agregar un miembro a una interfaz rompe todas las clases que implementan esa interfaz. No contendrán el nuevo método y ya no se compilarán. Cada implementador debe actualizar ese tipo para incluir al nuevo miembro. Elegir entre una clase base abstracta y una interfaz es una cuestión de cómo apoyar mejor sus abstracciones a lo largo del tiempo. Las interfaces son fijas: libera una interfaz como un contrato para un conjunto de funcionalidades que cualquier tipo puede implementar. Las clases base se pueden extender con el tiempo. Esas extensiones se convierten en parte de cada clase derivada. Los dos modelos se pueden mezclar para reutilizar el código de implementación mientras se admiten múltiples interfaces ". No contendrán el nuevo método y ya no se compilarán. Cada implementador debe actualizar ese tipo para incluir al nuevo miembro. Elegir entre una clase base abstracta y una interfaz es una cuestión de cómo apoyar mejor sus abstracciones a lo largo del tiempo. Las interfaces son fijas: libera una interfaz como un contrato para un conjunto de funcionalidades que cualquier tipo puede implementar. Las clases base se pueden extender con el tiempo. Esas extensiones se convierten en parte de cada clase derivada. Los dos modelos se pueden mezclar para reutilizar el código de implementación mientras se admiten múltiples interfaces ". No contendrán el nuevo método y ya no se compilarán. Cada implementador debe actualizar ese tipo para incluir al nuevo miembro. Elegir entre una clase base abstracta y una interfaz es una cuestión de cómo apoyar mejor sus abstracciones a lo largo del tiempo. Las interfaces son fijas: libera una interfaz como un contrato para un conjunto de funcionalidades que cualquier tipo puede implementar. Las clases base se pueden extender con el tiempo. Esas extensiones se convierten en parte de cada clase derivada. Los dos modelos se pueden mezclar para reutilizar el código de implementación mientras se admiten múltiples interfaces ". Libera una interfaz como un contrato para un conjunto de funcionalidades que cualquier tipo puede implementar. Las clases base se pueden extender con el tiempo. Esas extensiones se convierten en parte de cada clase derivada. Los dos modelos se pueden mezclar para reutilizar el código de implementación mientras se admiten varias interfaces ". Libera una interfaz como un contrato para un conjunto de funcionalidades que cualquier tipo puede implementar. Las clases base se pueden extender con el tiempo. Esas extensiones se convierten en parte de cada clase derivada. Los dos modelos se pueden mezclar para reutilizar el código de implementación mientras se admiten múltiples interfaces ".

"Las interfaces de codificación proporcionan una mayor flexibilidad a otros desarrolladores que la codificación a tipos de clase base".

"El uso de interfaces para definir API para una clase proporciona una mayor flexibilidad".

"Cuando su tipo expone propiedades como tipos de clase, expone toda la interfaz a esa clase. Usando interfaces, puede elegir exponer solo los métodos y propiedades que desea que los clientes usen".

"Las clases base describen e implementan comportamientos comunes a través de tipos concretos relacionados. Las interfaces describen piezas atómicas de funcionalidad que los tipos concretos no relacionados pueden implementar. Ambas tienen su lugar. Las clases definen los tipos que usted crea. Las interfaces describen el comportamiento de esos tipos como piezas funcionales. Si comprende las diferencias, creará diseños más expresivos que sean más resistentes frente al cambio. Utilice jerarquías de clase para definir tipos relacionados. Exponga la funcionalidad utilizando interfaces implementadas en esos tipos ".

John Connelly
fuente
2
Bueno, lo leí y pensé que era una buena respuesta.
Eric King
1
@ mc10 No estoy seguro de cuál es el problema. Hizo referencia a un libro y la mitad inferior de su respuesta son solo citas de ese libro que claramente le informa en caso de que no quiera perder su tiempo.
Pete
@Pete No dije que la respuesta es mala, sino que fue un poco demasiado larga. Dudo que necesitaras la cita completa a veces.
kevinji
3
jaja, si esto es tl; dr, no estoy seguro de que te va a gustar todo esto de StackExchange-high-quality-answers.
Nic
jaja, gracias chicos. Sí, se me ocurrió que la respuesta fue un poco larga, pero pensé que calificaría mi respuesta al incluir citas relevantes del Sr. Wagner que expongan las ventajas y desventajas de las interfaces frente a la herencia, así como los escenarios donde cada uno es más apropiado Quizás citar el libro directamente no agregó mucho valor a mi respuesta.
John Connelly
8

Una cosa que no se ha mencionado es la prueba: en todas las bibliotecas de simulación C #, así como en algunas para Java, las clases no se pueden burlar a menos que implementen una interfaz. Esto lleva a muchos proyectos siguiendo las prácticas Agile / TDD para dar a cada clase su propia interfaz.

Algunas personas consideran esta mejor práctica, porque "reduce el acoplamiento", pero no estoy de acuerdo, creo que es solo una solución a una deficiencia en el lenguaje.


Creo que las interfaces se usan mejor cuando tienes dos o más clases que, de manera abstracta, hacen "lo mismo", pero de diferentes maneras.

Por ejemplo, el marco .Net tiene múltiples clases que almacenan listas de cosas , pero todas almacenan esas cosas de diferentes maneras. Por lo tanto, tiene sentido tener una IList<T>interfaz abstracta , que se puede implementar utilizando diferentes métodos.

También debe usarlo cuando desee que 2+ clases sean intercambiables o reemplazables en el futuro. Si aparece una nueva forma de almacenar listas en el futuro, AwesomeList<T>suponiendo que haya utilizado IList<T>todo su código, cambiarlo para usarlo AwesomeList<T>solo significaría cambiar unas pocas docenas de líneas, en lugar de unos pocos cientos / mil.

BlueRaja - Danny Pflughoeft
fuente
5

El resultado principal de no usar la herencia y las interfaces cuando son apropiadas es un acoplamiento estrecho . Esto puede ser un poco difícil de aprender a reconocer, pero generalmente el síntoma más obvio es que cuando haces un cambio, con frecuencia tienes que revisar muchos otros archivos para hacer cambios en un efecto dominó.

Karl Bielefeldt
fuente
4

No, esto no es malo en absoluto. Deben usarse interfaces explícitas, si y solo si, dos clases con una interfaz común deben ser intercambiables en tiempo de ejecución. Si no es necesario que sean intercambiables, no haga que hereden. Es tan simple como eso. La herencia es frágil y debe evitarse siempre que sea posible. Si puedes evitarlo o usar genéricos en su lugar, entonces hazlo.

El problema es que, en lenguajes como C # y Java con genéricos débiles en tiempo de compilación, puede terminar violando DRY porque no hay forma de escribir un método que pueda manejar más de una clase a menos que todas las clases hereden de la misma base. Sin embargo, C # 4 dynamic puede lidiar con esto.

La cuestión es que la herencia es como variables globales: una vez que la agregue y su código dependa de ella, Dios lo ayudará a eliminarla. Sin embargo, puede agregarlo en cualquier momento, e incluso puede agregarlo sin alterar la clase base utilizando una especie de contenedor.

DeadMG
fuente
1
¿Motivo del voto negativo?
DeadMG
No estoy seguro, ten un voto a favor. Fue una buena respuesta.
Bryan Boettcher
3

Sí, no (o muy raramente) usar interfaces es probablemente algo malo. Las interfaces (en sentido abstracto, y la construcción del lenguaje C # / Java es una aproximación bastante buena de ese sentido abstracto) definen puntos de interacción explícitos entre sistemas y subsistemas. Esto ayuda a reducir el acoplamiento y hace que el sistema sea más fácil de mantener. Al igual que con cualquier cosa que mejore la capacidad de mantenimiento, se vuelve más importante cuanto más grande es un sistema.

Michael Borgwardt
fuente
3

No he usado una interfaz en años. Por supuesto, esto se debe a que he estado programando casi exclusivamente en Erlang durante años y el concepto completo de una interfaz simplemente no existe. (Lo más cercano que obtienes es un "comportamiento" y eso no es realmente lo mismo a menos que entrecerres los ojos y los mires por el rabillo del ojo).

Entonces, realmente, su pregunta depende del paradigma (OOP en este caso) y, además, es realmente bastante dependiente del lenguaje (hay lenguajes OOP sin interfaces).

SOLO MI OPINIÓN correcta
fuente
2

Si habla de usar Java, una razón para usar interfaces es que permiten el uso de objetos proxy sin bibliotecas de generación de código. Esto puede ser una ventaja sustancial cuando trabaja con un marco complejo como Spring. Además, algunas funcionalidades requieren interfaces: RMI es el ejemplo clásico de esto, ya que debe describir la funcionalidad que proporciona en términos de interfaces (que heredan de java.rmi.Remote) sin importar cómo las implemente.

Compañeros de Donal
fuente
1

Las cosas están cambiando ( MS Moles ), pero la razón principal por la que creo que es bueno codificar casi exclusivamente las interfaces es que son fáciles de burlar y encajan naturalmente en una arquitectura IoC.

En mi opinión, solo debe trabajar con interfaces o DAO completamente tontos siempre que sea posible. Una vez que entras en esta mentalidad, y comienzas a usar una biblioteca que no se expone a través de interfaces y hace todo a través de objetos concretos, tengo que ser honesto, todo se siente un poco torpe.


fuente
0

Para proyectos antiguos, uno usa interfaces para evitar referencias circulares, porque las referencias circulares podrían convertirse en un gran problema de mantenimiento a largo plazo.

Malo:

class B; // forward declaration
class A
{
  B* b;
};

class B
{
  A* a;
}

No está mal:

class PartOfClassB_AccessedByA
{
};

class A
{
  PartOfClassB_AccessedByA* b;
};

class B : public PartOfClassB_AccessedByA
{
  A* a;
}

Por lo general, A, B, PartOfClassB_AccessedByA implementado con archivos separados.

9dan
fuente
0

La programación basada en interfaz ayuda a hacer que el código sea más flexible y más fácil de probar. Las clases de implementación se pueden cambiar sin tocar el código del cliente [Flexibilidad]. Si bien probar el código uno puede reemplazar la programación real basada en la interfaz, ayuda a que el código sea más flexible y más fácil de probar. Las clases de implementación se pueden cambiar sin tocar el código del cliente [Flexibilidad]. Mientras se prueba el código uno, se puede reemplazar el objeto real con objetos simulados [Testability] .bject con objetos simulados [Testability].

Amit Patel
fuente