¿Necesito usar una interfaz cuando solo una clase la implementará?

243

¿No es el objetivo de una interfaz que múltiples clases se adhieran a un conjunto de reglas e implementaciones?

Lamin Sanneh
fuente
16
O para facilitar la prueba unitaria.
11
Permitir que múltiples clases implementen interfaces y que su código dependa de las interfaces es ESENCIAL para el aislamiento de las pruebas unitarias. Si está haciendo pruebas unitarias, tendrá otra clase implementando esa interfaz.
StuperUser
2
Discusión de Reddit sobre esta cuestión.
Yannis
66
Los campos y métodos públicos son una "interfaz" por derecho propio. Si la falta de polimorfismo se planifica intencionalmente, entonces no hay razón para usar una interfaz. La unidad que prueba otros mencionados es un uso planificado de polimorfismo.
mike30

Respuestas:

205

Estrictamente hablando, no, no, YAGNI aplica. Dicho esto, el tiempo que pasará creando la interfaz es mínimo, especialmente si tiene una práctica herramienta de generación de código que hace la mayor parte del trabajo por usted. Si no está seguro de si va a necesitar la interfaz o no, diría que es mejor equivocarse para apoyar la definición de una interfaz.

Además, el uso de una interfaz incluso para una sola clase le proporcionará otra implementación simulada para pruebas unitarias, una que no está en producción. La respuesta de Avner Shahar-Kashtan se expande sobre este punto.

Yannis
fuente
84
La prueba +1 significa que casi siempre tienes dos implementaciones de todos modos
jk.
24
@YannisRizos No está de acuerdo con su último punto debido a Yagni. Arrancar una interfaz desde un método público de clases es trivial después del hecho, al igual que reemplazar CFoo con IFoo en las clases consumidoras. No tiene sentido escribirlo antes de la necesidad.
Dan Neely
55
Todavía no estoy seguro de seguir tu razonamiento. Dado que las herramientas de generación de código hacen que agregarlo después del hecho sea aún más barato, veo aún menos razones para crear la interfaz antes de que tenga una necesidad explícita de ella.
Dan Neely
66
Creo que una interfaz faltante no es un buen ejemplo para YAGNI sino para una "ventana rota" y documentación faltante. Los usuarios de la clase están prácticamente obligados a codificar contra la implementación, en lugar de la abstracción como deberían.
Fabio Fracassi
10
¿Por qué alguna vez contaminarías tu base de código con cruft sin sentido solo para satisfacer algún marco de prueba? Quiero decir en serio, solo soy un chico del lado del cliente de JavaScript autodidacta que intenta solucionar WTF está mal con las implementaciones OOD de desarrolladores Java y C # que sigo encontrando en mi búsqueda de convertirme en un generalista más completo, pero ¿por qué no? ¿Le quitan el IDE de las manos y no le permiten recuperarlo hasta que aprenda a escribir un código limpio y legible cuando lo atrapan haciendo ese tipo de cosas en la universidad? Eso es simplemente obsceno.
Erik Reppen
144

Yo respondería que si necesita una interfaz o no, no depende de cuántas clases la implementen. Las interfaces son una herramienta para definir contratos entre múltiples subsistemas de su aplicación; Entonces, lo que realmente importa es cómo se divide su aplicación en subsistemas. Debe haber interfaces como el front-end para subsistemas encapsulados, sin importar cuántas clases los implementen.

Aquí hay una regla práctica muy útil:

  • Si hace que la clase se Foorefiera directamente a la clase BarImpl, se compromete firmemente a cambiar Foocada vez que cambie BarImpl. Básicamente los estás tratando como una unidad de código que se divide en dos clases.
  • Si hacer Fooreferencia a la interfaz Bar , que está en lugar de comprometerse a evitar cambios en Foocuando cambia BarImpl.

Si define interfaces en los puntos clave de su aplicación, piensa detenidamente en los métodos que deberían admitir y cuáles no, y comenta las interfaces claramente para describir cómo se supone que debe comportarse una implementación (y cómo no), la aplicación va a ser mucho más fácil de entender porque estas interfaces comentadas proporcionarán una especie de especificación de la aplicación de una descripción de cómo se pretende comportarse. Esto hace que sea mucho más fácil leer el código (en lugar de preguntar "qué diablos se supone que debe hacer este código", puede preguntar "cómo hace este código lo que se supone que debe hacer").

Además de todo esto (o en realidad por eso), las interfaces promueven una compilación separada. Dado que las interfaces son triviales para compilar y tienen menos dependencias que sus implementaciones, significa que si escribe clase Foopara usar una interfaz Bar, generalmente puede recompilar BarImplsin necesidad de recompilar Foo. En aplicaciones grandes, esto puede ahorrar mucho tiempo.

sacundim
fuente
14
Votaría esto mucho más de una vez, si pudiera. OMI la mejor respuesta a esta pregunta.
Fabio Fracassi
44
Si la clase solo realiza una función (es decir, solo tendría una interfaz definida para ella), ¿por qué no hacerlo a través de métodos públicos / privados?
Matthew Finlay
44
1. Organización del código; Tener la interfaz en su propio archivo que solo tiene firmas y comentarios de documentación ayuda a mantener limpio el código. 2. Marcos que lo obligan a exponer métodos que prefiere mantener en privado (por ejemplo, contenedores que inyectan dependencias a través de setters públicos). 3. Compilación separada, como ya se mencionó; si la clase Foodepende de la interfaz Bar, BarImplse puede modificar sin tener que volver a compilar Foo. 4. Control de acceso más detallado que las ofertas públicas / privadas (exponga la misma clase a dos clientes a través de diferentes interfaces).
sacundim
3
Y la última: 5. A los clientes (idealmente) no les debería importar cuántas clases tiene mi módulo o cuántas, o incluso poder decir. Todo lo que deberían ver es un conjunto de tipos , y algunas fábricas o fachadas para que la pelota ruede. Es decir, a menudo veo valor en encapsular incluso en qué clases se compone su biblioteca.
sacundim
44
@sacundim If you make class Foo refer directly to class BarImpl, you're strongly committing yourself to change Foo every time you change BarImplAl cambiar BarImpl, ¿cuáles son los cambios que se pueden evitar en Foo usando interface Bar? Dado que las firmas y la funcionalidad de un método no cambian en BarImpl, Foo no requerirá cambios incluso sin la interfaz (todo el propósito de la interfaz). Estoy hablando del escenario en el que solo una clase, es decir, BarImplimplementa Bar. Para el escenario de varias clases, entiendo el principio de inversión de dependencia y cómo es útil su interfaz.
Shishir Gupta
101

Las interfaces se designan para definir un comportamiento, es decir, un conjunto de prototipos de funciones / métodos. Los tipos que implementan la interfaz implementarán ese comportamiento, por lo que cuando se trata con un tipo de este tipo, usted sabe (en parte) qué comportamiento tiene.

No es necesario definir una interfaz si sabe que el comportamiento definido por ella se usará solo una vez. BESO (mantenlo simple, estúpido)

superM
fuente
No siempre, puede usar la interfaz en una clase si esa clase es una clase genérica.
John Isaiah Carmona
Además, puede introducir una interfaz cuando finalmente se necesite fácilmente en el IDE moderno con una refactorización de "interfaz de extracción".
Hans-Peter Störr
Considere una clase de utilidad donde solo hay métodos públicos estáticos y un constructor privado, perfectamente aceptable y promovido por autores como Joshua Bloch et al.
Darrell Teague el
63

Si bien, en teoría, no debería tener una interfaz solo por tener una interfaz, la respuesta de Yannis Rizos sugiere otras complicaciones:

Cuando escribe pruebas unitarias y utiliza marcos simulados como Moq o FakeItEasy (por nombrar los dos más recientes que he usado), está creando implícitamente otra clase que implementa la interfaz. Buscar el código o el análisis estático podría afirmar que solo hay una implementación, pero de hecho está la implementación simulada interna. Cada vez que comience a escribir simulacros, encontrará que extraer interfaces tiene sentido.

Pero espera hay mas. Hay más escenarios donde hay implementaciones de interfaz implícitas. El uso de la pila de comunicación WCF de .NET, por ejemplo, genera un proxy para un servicio remoto, que, nuevamente, implementa la interfaz.

En un entorno de código limpio, estoy de acuerdo con el resto de las respuestas aquí. Sin embargo, preste atención a los marcos, patrones o dependencias que tenga que puedan hacer uso de interfaces.

Avner Shahar-Kashtan
fuente
2
+1: No estoy seguro de que YAGNI se aplique aquí, ya que tener una interfaz y usar marcos (por ejemplo, JMock, etc.) que utilizan interfaces en realidad puede ahorrarle tiempo.
Deco
44
@Deco: los buenos frameworks de burla (JMock entre ellos) ni siquiera necesitan interfaces.
Michael Borgwardt
12
Crear una interfaz únicamente debido a una limitación de su marco burlón me parece una razón horrible. Usar, por ejemplo, EasyMock burlándose de una clase es tan fácil como una interfaz de todos modos.
Alb
8
Yo diría que es al revés. Usar objetos simulados en las pruebas significa crear implementaciones alternativas a sus interfaces, por definición. Esto es cierto tanto si crea sus propias clases de FakeImplementation o si deja que los frameworks de imitación hagan el trabajo pesado por usted. Puede haber algunos marcos, como EasyMock, que usan varios trucos y trucos de bajo nivel para burlarse de clases concretas, ¡y más poder para ellos! - pero conceptualmente, los objetos simulados son implementaciones alternativas a un contrato.
Avner Shahar-Kashtan
1
No estás disparando las pruebas en producción. ¿Por qué un simulacro para una clase que no necesitaba una interfaz, necesita una interfaz?
Erik Reppen
33

No, no los necesita, y considero que es un antipatrón crear interfaces automáticamente para cada referencia de clase.

Hacer un Foo / FooImpl para todo tiene un costo real. El IDE puede crear la interfaz / implementación de forma gratuita, pero cuando navega por el código, tiene la carga cognitiva adicional de F3 / F12 al foo.doSomething()llevarlo a la firma de la interfaz y no a la implementación real que desea. Además, tiene el desorden de dos archivos en lugar de uno para todo.

Por lo tanto, solo debe hacerlo cuando realmente lo necesite para algo.

Ahora abordando los contraargumentos:

Necesito interfaces para marcos de inyección de dependencia

Las interfaces para soportar marcos son heredadas. En Java, las interfaces solían ser un requisito para los proxies dinámicos, pre-CGLIB. Hoy, generalmente no lo necesitas. Se considera progreso y una bendición para la productividad del desarrollador que ya no los necesite en EJB3, Spring, etc.

Necesito simulacros para pruebas unitarias

Si escribe sus propios simulacros y tiene dos implementaciones reales, entonces una interfaz es apropiada. Probablemente no tendríamos esta discusión en primer lugar si su base de código tuviera un FooImpl y un TestFoo.

Pero si está utilizando un marco de imitación como Moq, EasyMock o Mockito, puede simular clases y no necesita interfaces. Es análogo a la configuración foo.method = mockImplementationen un lenguaje dinámico donde se pueden asignar métodos.

Necesitamos interfaces para seguir el principio de inversión de dependencia (DIP)

DIP dice que usted construye para depender de contratos (interfaces) y no de implementaciones. Pero una clase ya es un contrato y una abstracción. Para eso están las palabras clave públicas / privadas. En la universidad, el ejemplo canónico era algo así como una clase Matrix o Polinómica: los consumidores tienen una API pública para crear matrices, agregarlas, etc., pero no se les permite preocuparse si la matriz se implementa en forma dispersa o densa. No se requería IMatrix o MatrixImpl para probar ese punto.

Además, DIP a menudo se aplica en exceso en cada nivel de llamada de clase / método, no solo en los límites de los módulos principales. Una señal de que está aplicando DIP en exceso es que su interfaz e implementación cambian en el paso de bloqueo, de modo que tiene que tocar dos archivos para hacer un cambio en lugar de uno. Si DIP se aplica adecuadamente, significa que su interfaz no debería cambiar con frecuencia. Además, otra señal es que su interfaz solo tiene un consumidor real (su propia aplicación). Historia diferente si está creando una biblioteca de clase para el consumo en muchas aplicaciones diferentes.

Este es un corolario al punto del tío Bob Martin sobre burlarse: solo debería burlarse de los principales límites arquitectónicos. En una aplicación web, el acceso HTTP y DB son los límites principales. Todas las llamadas de clase / método intermedias no lo son. Lo mismo va para DIP.

Ver también:

wrschneider
fuente
44
Las clases de burla en lugar de las interfaces (al menos en Java y C #) deben considerarse obsoletas, ya que no hay forma de evitar que se ejecute el constructor de la superclase, lo que puede hacer que su objeto simulado interactúe con el entorno de maneras no deseadas. Burlarse de una interfaz es más seguro y fácil porque no tiene que pensar en el código del constructor.
Julio
44
No he tenido problemas con las clases de burla, pero me ha frustrado que la navegación IDE no funcione como se esperaba. Resolver un problema real supera a uno hipotético.
wrschneider
1
@Jules Puede burlarse de una clase concreta, incluido su constructor en Java.
Assylias
1
@assylias, ¿cómo evitas que se ejecute el constructor?
Jules
2
@Jules Depende de su marco de imitación: con jmockit, por ejemplo, puede escribir new Mockup<YourClass>() {}y toda la clase, incluidos sus constructores, se burlan, ya sea una interfaz, una clase abstracta o una clase concreta. También puede "anular" el comportamiento del constructor si lo desea. Supongo que hay formas equivalentes en Mockito o Powermock.
Assylias
22

Parece que las respuestas en ambos lados de la cerca se pueden resumir en esto:

Diseñe bien y coloque interfaces donde se necesiten interfaces.

Como señalé en mi respuesta a la respuesta de Yanni , no creo que puedas tener una regla dura y rápida sobre las interfaces. La regla debe ser, por definición, flexible. Mi regla sobre las interfaces es que se debe usar una interfaz en cualquier lugar donde esté creando una API. Y se debe crear una API en cualquier lugar que esté cruzando el límite de un dominio de responsabilidad a otro.

Para un ejemplo (terriblemente ideado), digamos que estás construyendo una Carclase. En su clase, ciertamente necesitará una capa de interfaz de usuario. En este ejemplo particular, se toma la forma de un IginitionSwitch, SteeringWheel, GearShift, GasPedal, y BrakePedal. Como este auto contiene un AutomaticTransmission, no necesitas un ClutchPedal. (Y como este es un automóvil terrible, no hay aire acondicionado, radio o asiento. De hecho, también faltan las tablas del piso, ¡solo tienes que agarrarte al volante y esperar lo mejor!)

Entonces, ¿cuál de estas clases necesita una interfaz? La respuesta podría ser todas ellas, o ninguna, dependiendo de su diseño.

Podría tener una interfaz similar a esta:

Interface ICabin
    Event IgnitionSwitchTurnedOn()
    Event IgnitionSwitchTurnedOff()
    Event BrakePedalPositionChanged(int percent)
    Event GasPedalPositionChanged(int percent)
    Event GearShiftGearChanged(int gearNum)
    Event SteeringWheelTurned(float degree)
End Interface

En ese punto, el comportamiento de esas clases se convierte en parte de la interfaz / API ICabin. En este ejemplo, las clases (si hay algunas) son probablemente simples, con algunas propiedades y una función o dos. Y lo que está afirmando implícitamente con su diseño es que estas clases existen únicamente para apoyar cualquier implementación concreta de ICabin que tenga, y no pueden existir por sí mismas o no tienen sentido fuera del contexto de ICabin.

Es la misma razón por la que no realiza una prueba unitaria de los miembros privados: existen solo para admitir la API pública y, por lo tanto, su comportamiento debe probarse probando la API.

Entonces, si su clase existe únicamente para admitir otra clase, y conceptualmente la ve como que realmente no tiene su propio dominio, entonces está bien omitir la interfaz. Pero si su clase es lo suficientemente importante como para considerar que ha crecido lo suficiente como para tener su propio dominio, entonces continúe y dele una interfaz.


EDITAR:

Con frecuencia (incluso en esta respuesta) leerá cosas como 'dominio', 'dependencia' (frecuentemente junto con 'inyección') que no significan nada para usted cuando comienza a programar (seguro que no significa algo para mí). Para dominio, significa exactamente cómo suena:

El territorio sobre el cual se ejerce el dominio o la autoridad; las posesiones de un soberano o una comunidad, o similares. También se usa figurativamente. [WordNet sentido 2] [1913 Webster]

En los términos de mi ejemplo, consideremos el IgnitionSwitch. En un automóvil con espacio para carnes, el interruptor de encendido es responsable de:

  1. Autenticar (no identificar) al usuario (necesitan la clave correcta)
  2. Proporcionar corriente al motor de arranque para que realmente pueda arrancar el automóvil
  3. Proporcionar corriente al sistema de encendido para que pueda continuar funcionando
  4. Apagando la corriente para que el auto se detenga.
  5. Dependiendo de cómo lo veas, en la mayoría (¿todos?) De los autos más nuevos hay un interruptor que evita que la llave se retire del encendido mientras la transmisión está fuera del estacionamiento, por lo que esto podría ser parte de su dominio. (En realidad, significa que tengo que repensar y rediseñar mi sistema ...)

Esas propiedades conforman el dominio de IgnitionSwitch, o en otras palabras, de lo que sabe y es responsable.

El IgnitionSwitchno es responsable de la GasPedal. El interruptor de encendido ignora completamente el pedal del acelerador en todos los sentidos. Ambos operan de manera completamente independiente el uno del otro (¡aunque un automóvil sería bastante inútil sin ambos!).

Como dije originalmente, depende de su diseño. Puede diseñar un IgnitionSwitchque tenga dos valores: On ( True) y Off ( False). O puede diseñarlo para autenticar la clave provista por él y una gran cantidad de otras acciones. Esa es la parte difícil de ser desarrollador: decidir dónde dibujar las líneas en la arena, y sinceramente, la mayoría de las veces es completamente relativo. Sin embargo, esas líneas en la arena son importantes: ahí es donde está su API y, por lo tanto, donde deberían estar sus interfaces.

Wayne Werner
fuente
¿Podría por favor dar más detalles sobre lo que quiere decir con "tener su propio dominio"?
Lamin Sanneh
1
@LaminSanneh, elaborado. ¿Eso ayuda?
Wayne Werner
8

No (YAGNI) , a menos que esté planeando escribir pruebas para otras clases usando esta interfaz, y esas pruebas se beneficiarían de burlarse de la interfaz.

stijn
fuente
8

De MSDN :

Las interfaces se adaptan mejor a situaciones en las que sus aplicaciones requieren muchos tipos de objetos posiblemente no relacionados para proporcionar cierta funcionalidad.

Las interfaces son más flexibles que las clases base porque puede definir una única implementación que puede implementar múltiples interfaces.

Las interfaces son mejores en situaciones en las que no necesita heredar la implementación de una clase base.

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.

En general, en el caso de una sola clase, no será necesario implementar una interfaz, pero teniendo en cuenta el futuro de su proyecto, podría ser útil definir formalmente el comportamiento necesario de las clases.

lwm
fuente
5

Para responder a la pregunta: hay más que eso.

Un aspecto importante de una interfaz es la intención.

Una interfaz es "un tipo abstracto que no contiene datos, pero expone comportamientos" - Interfaz (informática) Entonces, si este es un comportamiento, o un conjunto de comportamientos, que la clase admite, es probable que una interfaz sea el patrón correcto. Sin embargo, si el (los) comportamiento (s) es (n) intrínseco al concepto incorporado por la clase, entonces es probable que no desee una interfaz en absoluto.

La primera pregunta que debe hacerse es cuál es la naturaleza de la cosa o proceso que está tratando de representar. Luego continúe con las razones prácticas para implementar esa naturaleza de una manera determinada.

Joshua Drake
fuente
5

Desde que hizo esta pregunta, supongo que ya ha visto los intereses de tener una interfaz que oculte múltiples implementaciones. Esto puede manifestarse por el principio de inversión de dependencia.

Sin embargo, la necesidad de tener una interfaz o no no depende del número de implementaciones. La función real de una interfaz es que define un contrato que establece qué servicio se debe proporcionar en lugar de cómo se debe implementar.

Una vez definido el contrato, dos o más equipos pueden trabajar de forma independiente. Digamos que está trabajando en un módulo A y depende del módulo B, el hecho de crear una interfaz en B le permite continuar su trabajo sin preocuparse por la implementación de B porque la interfaz oculta todos los detalles. Por lo tanto, la programación distribuida se hace posible.

Aunque el módulo B solo tiene una implementación de su interfaz, la interfaz sigue siendo necesaria.

En conclusión, una interfaz oculta los detalles de implementación de sus usuarios. La programación para la interfaz ayuda a escribir más documentos porque se debe definir el contrato, escribir más software modular, promover pruebas unitarias y acelerar la velocidad de desarrollo.

Hui Wang
fuente
2
Cada clase puede tener una interfaz pública (los métodos públicos) y una interfaz privada (los detalles de implementación). Podría argumentar que la interfaz pública de la clase es el contrato. No necesita un elemento adicional para trabajar en ese contrato.
Fuhrmanator
4

Todas las respuestas aquí son muy buenas. De hecho, la mayoría de las veces no necesita implementar una interfaz diferente. Pero hay casos en los que es posible que desee hacerlo de todos modos. Aquí hay un caso donde lo hago:

La clase implementa otra interfaz que no quiero exponer
Happen a menudo con la clase de adaptador que une el código de terceros.

interface NameChangeListener { // Implemented by a lot of people
    void nameChanged(String name); 
} 

interface NameChangeCount { // Only implemented by my class
    int getCount();
}

class NameChangeCounter implements NameChangeListener, NameChangeCount {
    ...
}

class SomeUserInterface {
    private NameChangeCount currentCount; // Will never know that you can change the counter
}

La clase utiliza una tecnología específica que no debería filtrarse
principalmente cuando interactúa con bibliotecas externas. Incluso si solo hay una implementación, uso una interfaz para asegurarme de no introducir un acoplamiento innecesario con la biblioteca externa.

interface SomeRepository { // Guarantee that the external library details won't leak trough
    ...
}

class OracleSomeRepository implements SomeRepository { 
    ... // Oracle prefix allow us to quickly know what is going on in this class
}

Comunicación entre capas
Incluso si solo una clase de IU implementa alguna vez una de las clases de dominio, permite una mejor separación entre esas capas y, lo más importante, evita la dependencia cíclica.

package project.domain;

interface UserRequestSource {
    public UserRequest getLastRequest();
}

class UserBehaviorAnalyser {
    private UserRequestSource requestSource;
}

package project.ui;

class OrderCompleteDialog extends SomeUIClass implements project.domain.UserRequestSource {
    // UI concern, no need for my domain object to know about this method.
    public void displayLabelInErrorMode(); 

    // They most certainly need to know about *that* though
    public UserRequest getLastRequest();
}

Solo un subconjunto del método debe estar disponible para la mayoría de los objetos.
Principalmente sucede cuando tengo algún método de configuración en la clase concreta

interface Sender {
    void sendMessage(Message message)
}

class PacketSender implements Sender {
    void sendMessage(Message message);
    void setPacketSize(int sizeInByte);
}

class Throttler { // This class need to have full access to the object
    private PacketSender sender;

    public useLowNetworkUsageMode() {
        sender.setPacketSize(LOW_PACKET_SIZE);
        sender.sendMessage(new NotifyLowNetworkUsageMessage());

        ... // Other details
    }
}

class MailOrder { // Not this one though
    private Sender sender;
}

Así que al final uso la interfaz por la misma razón que uso el campo privado: otro objeto no debería tener acceso a cosas a las que no debería acceder. Si tengo un caso así, presento una interfaz incluso si solo una clase lo implementa.

Laurent Bourgault-Roy
fuente
2

Las interfaces son realmente importantes, pero intenta controlar la cantidad de ellas que tienes.

Después de haber creado interfaces para casi todo, es fácil terminar con un código de "espagueti cortado". Me refiero a la mayor sabiduría de Ayende Rahien, quien ha publicado algunas palabras muy sabias sobre el tema:

http://ayende.com/blog/153889/limit-your-abstraction-analyzing-a-ddd-application

Esta es su primera publicación de toda una serie, ¡así que sigue leyendo!

Lord Spa
fuente
El código de 'espagueti picado' también se conoce como código de ravioles c2.com/cgi/wiki?RavioliCode
CurtainDog
A mí me suena más a código de lasaña o código de baklava: código con demasiadas capas. ;-)
dodgy_coder
2

Una razón por la que aún puede querer introducir una interfaz en este caso es seguir el Principio de Inversión de Dependencia . Es decir, el módulo que utiliza la clase dependerá de una abstracción de la misma (es decir, la interfaz) en lugar de depender de una implementación concreta. Desacopla los componentes de alto nivel de los componentes de bajo nivel.

dodgy_coder
fuente
2

No hay una razón real para hacer nada. Las interfaces son para ayudarlo y no al programa de salida. Entonces, incluso si la interfaz es implementada por un millón de clases, no hay una regla que diga que tienes que crear una. Usted crea uno para que cuando usted, o cualquier otra persona que use su código, quiera cambiar algo que se filtre en todas las implementaciones. La creación de una interfaz lo ayudará en todos los casos futuros en los que desee crear otra clase que la implemente.

John Demetriou
fuente
1

No siempre es necesario definir una interfaz para una clase.

Los objetos simples como los objetos de valor no tienen implementaciones múltiples. Tampoco necesitan que se burlen de ellos. La implementación se puede probar por sí misma y cuando se prueban otras clases que dependen de ellas, se puede usar el objeto de valor real.

Recuerde que crear una interfaz tiene un costo. Debe actualizarse a lo largo de la implementación, necesita un archivo adicional y algunos IDE tendrán problemas para ampliar la implementación, no la interfaz.

Por lo tanto, definiría interfaces solo para clases de nivel superior, donde desea una abstracción de la implementación.

Tenga en cuenta que con una clase obtiene una interfaz de forma gratuita. Además de la implementación, una clase define una interfaz a partir del conjunto de métodos públicos. Esa interfaz es implementada por todas las clases derivadas. No se trata estrictamente de una interfaz, pero se puede usar exactamente de la misma manera. Así que no creo que sea necesario recrear una interfaz que ya existe bajo el nombre de la clase.

Florian F
fuente