2010-12-09 17 views
10

Últimamente, he estado leyendo publicaciones que hablan de la supuesta noción errónea de que las interfaces son abstracciones. Una de esas publicaciones es http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstractions.aspxLas interfaces (interfaz/clase abstracta) no son abstracciones?

Estoy un poco confundido. Si no tengo interfaces (interfaz/clase abstracta), ¿cómo inyectaré mis dependencias y me burlaré de ellas?

Además, escuché a la gente hablar acerca de no usar interfaces que tiene un solo implementador. Como este blog aquí - http://simpleprogrammer.com/2010/11/02/back-to-basics-what-is-an-interface/

Ahora todo esto, ¿no viola el principio - Programa a una interfaz y no a la implementación?

Respuesta

5

La programación en una interfaz en lugar de una implementación se trata más que nada del uso de abstracción y encapsulación de datos.

Cuando decimos "interfaz" en términos de programación a una interfaz. Ese tipo de interfaz significa los métodos y propiedades exteriores de una clase. No tiene que ser una interfaz de nivel de idioma. (La interfaz de palabras clave.)

Debe esforzarse para asegurarse de que su código no dependa de los detalles internos de otras clases.

+0

* Cuando decimos "interfaz" en términos de programación a una interfaz. Ese tipo de interfaz significa los métodos y propiedades exteriores de una clase. No tiene que ser una interfaz de nivel de idioma. * Entonces, ¿me equivoqué todo el tiempo? Entonces, ¿una clase concreta puede ser una interfaz de acuerdo a usted? – Sandbox

+4

Correcto. Más específicamente, las firmas públicas de los métodos y propiedades conforman la interfaz de esa clase. Cada vez que creas una clase, lo que sea que elijas exponer se convierte en parte de la interfaz externa de esa clase. Al cambiarlo, rompe aquellos que dependen de él. Si otra clase confía más en su interfaz (confía en los detalles específicos de implementación dentro de la clase, por ejemplo, cómo se ordena una lista o se almacenan los datos), incluso cambiar pequeñas cosas internas los rompería. –

+0

Pero cuando el código se refiere a un tipo concreto, ¿no significa que si tenemos otra clase mañana de tipo similar, tendremos que cambiar el código?En cambio, con interfaces/clases abstractas puede cambiar una implementación diferente en tiempo de ejecución. – Sandbox

3

Mientras no exagere, creo que es mejor que cree una interfaz.

He aquí un caso de uso que tengo frecuentemente cuando tener un solo implementador es (en mi opinión) perfectamente correcto: tiene un componente Swing, digamos que es CarComparisonResultsPanel, que permite al usuario ver los resultados de la comparación entre automóviles . Como usuario del panel, prefiero tener una interfaz CarComparisonResult con solo getCarSimilarities() y getCarDifferences() que una implementación de JPanel que implemente esos métodos, así como docenas de otros.

EDITAR: Para aclarar mi punto de vista "no hacerlo más", estos son algunos ejemplos de exageración: interfaces para fábricas, constructores, clases de ayuda/utilidad, componentes de GUI que no agregan público relevante métodos para su padre, ...

+0

De hecho estaría de acuerdo contigo allí. En ese caso, está utilizando una interfaz para reducir la complejidad y la visibilidad del código con CarComparisonResultsPanel. –

+0

¿Cómo se puede decidir no exagerar? Me refiero a que con las interfaces/clases abstractas de referencia de código de cliente siempre se puede cambiar una implementación en tiempo de ejecución. Además, si no tienes interfaces, ¿cómo vas a burlarte de ellas? Estas dos razones me obligan a pensar que las interfaces/clases abstractas son perfectamente válidas en todos los casos. – Sandbox

+0

Tengo una serie de publicaciones básicas en mi blog http://simpleprogrammer.com que profundizan sobre las interfaces y este tema exacto, explorando DI y IoC, etc., es posible que desee verificarlo. –

0

Los principios detrás de la programación de una interfaz no tienen que ser dejados solo para situaciones de interfaz. Cuando diseña sus interfaces, las preguntas generales que hace son: "¿Dónde estoy esperando que se consuma? ¿Por quién? ¿Y con qué propósito?" Preguntas que deben hacerse incluso cuando se crean clases de implementación.

Puede ser que, al diseñar una interfaz, se dé cuenta de que realmente no necesita hacer de esto una interfaz, y permitir la sobrecarga y la herencia será suficiente para la prueba. Como se menciona en el primer artículo, si consistentemente terminas con una correlación 1: 1 entre objetos e interfaces sin otro propósito que no sea "Estoy programando contra interfaces", simplemente estás haciendo un lío de tu código.

Pero eso no significa que no pueda seguir adelante y diseñar la clase como si estuviera creando una interfaz/clase base para ella, con un conjunto de métodos/propiedades/campos genéricos que proporcionan funcionalidad básica y luego agregue otros métodos/propiedades/campos más específicos para la implementación. Hacerlo todavía, IMO, caería dentro de los principios de programación a una interfaz. También dejaría la puerta abierta para que extraigas una interfaz/clase base cuando surja una necesidad clara y definida.

+0

Yo diría que permitir sobrecargar y heredar solo para fines de prueba es mucho, mucho peor que crear una interfaz 1: 1. Por herencia, estás introduciendo una nueva complejidad a tu API pública y abriendo muchas posibilidades para romper el comportamiento de tu clase. La interfaz 1: 1 al menos no tiene tales efectos secundarios. – NOtherDev

5

yo diría que no estoy de acuerdo con muchos de los puntos en los artículos vinculados:

  • las interfaces son contratos. El contrato tiene dos partes: el método firma (puramente sintáctico) y la documentación .

  • interfaces son abstracciones. No pude ver un ejemplo de violación de LSP. El ejemplo IRectangle no es bueno en absoluto. Lo mismo puede decirse sobre Set extends Collection, donde no se permite agregar duplicados. Si le pasaron un Collection, le sorprenderá que no permita duplicados. Con las interfaces Collection esto se soluciona documentando que los implementadores pueden agregar restricciones

  • Las abstracciones con fugas son inevitables. Pero esto depende completamente del diseñador. Y por cierto, "las interfaces son abstracciones con fugas" significa que son abstracciones.

  • Parece que los muchachos han perdido la "exposición" a las pruebas unitarias. Las implementaciones simuladas son una muy buena razón para usar una interfaz (aunque también puede simular clases concretas).

  • Un muy buen ejemplo de nuestro proyecto actual - al principio tenemos solo una implementación DAO - uno que toma cosas de la base de datos. Pero más tarde cambiamos algunas de las operaciones a un motor de búsqueda dedicado. Agregamos otra implementación de DAO, y ahí vamos. Así que tener una interfaz con una implementación inicialmente pagó.

  • Btw, inicialmente SortedSet tenía solo una implementación en el JDK - TreeSet. Ahora tiene dos. Y muchos más de las bibliotecas externas.

  • Finalmente, las interfaces (como constructo de lenguaje) son una forma de describir la funcionalidad de una clase con la característica adicional de no permitir el deslizamiento de la implementación. Es decir, las interfaces son una forma difícil de utilizar.

Dicho todo esto, no necesita una interfaz para todo. Pero depende del caso concreto. Yo, por ejemplo, no uso interfaces para clases de ayuda. Y un punto válido de los artículos es que la "programación de una interfaz" no necesariamente incluye la palabra clave interface. La "interfaz pública" de una clase es (teóricamente) el conjunto de sus métodos públicos.

+1

Las implementaciones simuladas no son una buena razón para usar una interfaz, son un mal necesario, si necesita una implementación simulada. El problema es que nuestros lenguajes de programación no respaldan la idea de proporcionar implementaciones simuladas, por lo que abusamos de la interfaz para lograr el resultado. Mientras, lo hago yo mismo, creo que todavía es importante entender que está mal. Pagamos un precio por la interfaz adicional, el precio es la complejidad y la falta de cohesión, porque las cosas relacionadas ya no están unidas directamente en nuestro código. –

+0

como dije, los simulacros se pueden hacer en clases concretas también (en Java, al menos, hay algunos frameworks potentes). Sin embargo, no creo que esté mal usar burlas en las interfaces. Esta es una implementación diferente del mismo concepto, ¿verdad? El hecho de que se use en un entorno específico (prueba de unidad) no le quita nada; sigue siendo una interfaz con 2 implementaciones válidas. – Bozho

+0

Además, no debería usar clases de ayuda, no tienen una responsabilidad definida. Ellos violan OO. –

Cuestiones relacionadas