¿Deben todas las clases que escribo adherirse a una interfaz?

10

Estoy escribiendo un juego en Typecript, y decidí al entrar que iba a tratar de adherirme a la idea de " programación basada en interfaz ", donde escribes código basado en una interfaz, en lugar de la implementación, de un objeto.

Escribí una buena cantidad de interfaces y clases que las implementan, luego di un paso atrás y me di cuenta de que las clases eran lo suficientemente simples como para que nunca necesite cambiar la implementación, ya que en realidad solo hay una forma de hacer lo que clase hace (mover una Phaser.Spritede forma restringida para actuar como un tanque).

Entonces recuerdo haber leído hace unos años sobre la idea de YAGNI , que básicamente es que no debes manipular excesivamente tu código para incluir cosas que quizás nunca uses.

Siguiendo las mejores prácticas, ¿debería cada clase implementar una interfaz, o debería limitarla a clases que espera que se intercambien en el futuro?

Carcigenicate
fuente
Recuerde, cuando usa una clase real como parámetro, también está codificando a una interfaz, a la interfaz de esta clase. Nadie lo obliga a usar esa clase específica, también podría heredarla y proporcionar una funcionalidad completamente nueva, pero eso no parece correcto. Las interfaces existen para hacer que las personas puedan entender mejor la idea. Con eso triste, no, realmente no necesitas interfaces para todo.
Andy
1
Posible duplicado de La necesidad de agregar una interfaz a cada clase
mosquito

Respuestas:

6

La razón para tener interfaces es porque simplifica el polimorfismo. Lo que significa que puede enviar instancias por contrato en lugar de conocer su implementación real. Por ejemplo, puede enviar un "Lector" a un método, de modo que dicho método llamado pueda usar su método "read ()". Al declarar una interfaz "Lector", puede hacer que cualquier objeto se ajuste a este contrato, implementando los métodos que especifica. De esta manera, cualquier persona que llama puede asumir que existirán ciertos métodos, incluso si los objetos subyacentes al contrato pueden ser completamente diferentes.

Esto desacopla el polimorfismo de una clase base y lo hace posible también entre las fronteras de la cadena de clase, al implicar un contrato.

Ahora ... Esto solo es útil si tiene la necesidad de que múltiples cadenas de herencia actúen de la misma manera, o si tendrá muchas clases base con comportamiento común que querrá transmitir a otros usuarios.

Si solo tiene UNA cadena de herencia (clase base-> subclase) o solo la base, o no tiene necesidad de PASAR los objetos relacionados a otra persona o usarlos genéricamente, entonces no agregaría implementaciones de interfaz, ya que esa noción es entonces inútil.

Richard Tyregrim
fuente
También agregaría que las interfaces deberían modelar abstracciones, así que no las cree simplemente alzando a todos los miembros públicos de una clase. Piense en lo que representa esa clase y solo ponga esas cosas en la interfaz que cualquier objeto de ese tipo debería tener. También puede terminar creando múltiples interfaces (por ejemplo, Movesy Shootspara su ejemplo de tanque) para una sola clase.
TMN
7

Si no está seguro de si realmente necesita las interfaces, entonces probablemente no. Este es el núcleo del principio YAGNI. Cuando necesita poder intercambiar la implementación, entonces introduce una interfaz.

JacquesB
fuente
6

Crear una interfaz para cada clase es un poco exagerado. Desde una perspectiva puramente orientada a objetos, cada clase ya tiene una interfaz . Una interfaz no es más que los métodos públicos y los miembros de datos de una clase.

Normalmente usamos "interfaz" para referirnos a "una clase Java definida usando la interfacepalabra clave" o "una clase C ++ con solo funciones virtuales públicas y puras". Estas son abstracciones útiles, porque desacoplan la interfaz de una clase de su implementación.

Con eso en mente, use interfaces cuando sea apropiado.

  • ¿Habrá múltiples implementaciones para una interfaz? Si es así, esta situación puede ser un candidato para extraer métodos comunes de cara al público en una interfaz.

  • ¿Transmitiré implementaciones de una interfaz potencial a otros módulos que no deberían conocer el funcionamiento interno de mi módulo? Una interfaz puede ser útil aquí, porque reduce el tamaño del punto de contacto entre los módulos.

Observe las palabras de comadreja de arriba: "puede" ser un candidato, "puede ser" útil. No existe una regla estricta que diga "sí" o "no" para una situación dada.

Dicho esto, lo más probable es que tener una interfaz para todo sea excesivo. Si ves este patrón, llegarás lejos:

interface I {
  int getA()
  int getB()
  ...
  int getY()
  int getZ()
}

class C : I {
  int getA() { ... }
  int getB() { ... }
  ...
  int getY() { ... }
  int getZ() { ... }
}

fuente
Una razón más para las interfaces es si su sistema de prueba lo hace necesario, lo que puede depender de su idioma y marco de prueba. Espero que no necesites hacer esto, por supuesto.
Darien
@Darien: La razón por la que un sistema de prueba puede requerir interfaces es porque la prueba en realidad está utilizando una implementación diferente (simulada), lo que lo lleva de vuelta a la primera viñeta de cuándo es apropiada una interfaz.
Bart van Ingen Schenau
Algunas cosas geniales aquí. Solo reflexionando sobre esto: una interfaz no es más que los métodos públicos y los miembros de datos de una clase . Si bien esto es cierto para la implementación de una interfaz , ciertamente no es cierto para una interfaz que nunca se implementa, aunque está garantizado, esto sería una especie de olor a código.
Robbie Dee
@RobbieDee es cierto, por ejemplo, para un Java interface, da la casualidad de que todo en Java interfacetambién es su interfaz pública (concepto OO).
¡Todo el mundo! Escriba las oraciones segunda y tercera de la respuesta. Laminarlo. Ponlo en tu billetera. Referencia a menudo.
radarbob
5

Puede ser muy tentador para los nuevos desarrolladores pensar en las interfaces como un inconveniente que simplemente agregas solo porque te dicen que es la "mejor práctica". Si está haciendo esto a ciegas, huele a programación de culto de carga .

Hay una serie de muy buenas razones por las que debería considerar las interfaces para desarrollos más grandes en lugar de agrupar un conjunto de clases.

Marcos burlones

Si desea probar una aplicación de varias capas sin tener que crear objetos para las diversas capas, sin duda querrá usar marcos de imitación para simular las capas. Las interfaces se usan ampliamente aquí.

Inyección de dependencia

Si bien han caído en desgracia debido a la hinchazón que agregan, la idea es sólida: la capacidad de intercambiar concreciones simplemente en función de una interfaz. El principio también se puede encontrar en muchos patrones de diseño, como el patrón de fábrica.


Estos enfoques se resumen en la D de principios SÓLIDOS . El problema de esto es: use abstracciones, no concreciones.

Al igual que los patrones de diseño en sí, cuándo usarlos es una decisión decisiva. El punto clave es entender cómo las interfaces son útiles, no solo pegarlas en tus clases porque sientes que tienes que hacerlo. Hay una buena discusión de los diversos méritos de DIP y YAGNI aquí .

Robbie Dee
fuente
Tenga en cuenta que la inyección de dependencia y los contenedores de IoC son dos cosas completamente diferentes (una es un principio de diseño y la otra es una forma concreta de poner en práctica ese principio mediante el uso de varios marcos). Puede usar DI sin usar un contenedor de IoC.
Sara
@kai "Puede usar DI sin usar un contenedor IoC" . Creo que las tiendas de desarrollo más maduras pueden (y lo hacen). Simplemente no hay necesidad de contaminar el código de lo que aparentemente es un concepto simple. Joel es de una opinión similar.
Robbie Dee
YAGNI es muy tramposa. Cualquiera que sea la filosofía, en la mayoría de los casos, en realidad, YAGNI se utiliza como excusa para cortar esquinas. Evitar el acoplamiento debe tomarse más en serio. Es frustrante ver en muchas reuniones de scrum, un desarrollador se llama a sí mismo bloqueado porque alguien más no terminó su trabajo. ¿Cómo es que bloquear a otro desarrollador le está ahorrando tiempo a alguien? Mi sugerencia es usar una interfaz para evitar el acoplamiento. Por supuesto, uno no tiene que usar una interfaz para las clases de Modelo.
Ripal Barot