2011-02-16 13 views
12

Un nuevo colaborador mío que estaba revisando algo de código que había escrito me dijo que no estaba acostumbrado a ver las interfaces utiliza directamente en código Java, por ejemplo:estilo de código Java - Interfaces vs. clases abstractas

public interface GeneralFoo { ... } 

public class SpecificFoo implements GeneralFoo { ... } 

public class UsesFoo { 
    GeneralFoo foo = new SpecificFoo(); 
} 

lugar, esperando ver

public interface GeneralFoo { ... } 

public abstract class AbstractFoo implements GeneralFoo { ... } 

public class SpecificFoo extends AbstractFoo { ... } 

public class UsesFoo { 
    AbstractFoo foo = new SpecificFoo(); 
} 

puedo ver cuando este patrón tiene sentido, si toda la funcionalidad SpecificFoos social mediante AbstractFoo, pero si los diversos Foos tienen completamente diferentes implementaciones internas (o no nos importa cómo un Foo do Bar específico, siempre que lo haga), ¿hay algún daño? n usar una interfaz directamente en el código? Me doy cuenta de que esto es probablemente una cosa de tomate/tomate hasta cierto punto, pero tengo curiosidad por saber si hay una ventaja para el segundo estilo, o desventaja para el primer estilo, que me estoy perdiendo.

+0

posible duplicado de [Interfaz vs clase base] (http://stackoverflow.com/questions/56867/interface-vs-base-class) – thecoop

+1

@thecoop: casi un duplicado de ese, pero todavía no es . Éste compara la clase de interfaz frente a la clase de clase base de interfaz, y la otra compara clase de interfaz frente a clase de clase base. Además, este es específico de Java. –

+0

¡Suena como un dolor dogmático en el culo! – Jonathan

Respuesta

15

Si no necesita una clase abstracta con ciertos detalles comunes a todas las implementaciones, entonces no hay una necesidad real de una clase abstracta. La complejidad a menudo se agrega a las aplicaciones porque se percibe la necesidad de admitir funciones futuras que aún no se han definido. Quédate con lo que funciona, y refactoriza después.

+2

+1 a esto. Es muy común encontrar una interfaz, parcialmente implementada por una clase abstracta, con solo una clase base que proporciona la funcionalidad completamente definida. En el código maduro, tales casos piden la refactorización para fusionar el resumen y la clase base, y posiblemente (dependiendo de la estructura del código) la refactorización adicional para encubrir la interfaz/implementación única resultante en una sola clase. –

3

Depende solo de su problema.

Si solo usa interfaces, entonces si todas sus clases tienen un mismo método, debería implementarse de forma redundante (o pasar a una clase Util).

Por otro lado, si escribe una clase abstracta intermedia, ha resuelto ese problema, pero ahora su subclase puede no ser una subclase de otra clase, debido a la ausencia de herencia múltiple en Java. Si ya era necesario ampliar alguna clase, esto no es posible.

Así, poco - es una solución de compromiso. Use el que sea mejor en su caso particular.

5

No, ella no tiene experiencia, no está bien. Se prefiere usar interfaces, y la escritura de superclases abstractas redundantes por redundancia es redundante.

UsesFoo debe tener en cuenta el comportamiento especificado por la interfaz, no sobre la superclase de sus dependencias.

1

Se considera una mala práctica para algunos declarar variables por sus firmas AbstractFoo, ya que la clase UsesFoo está acoplada a algunos de los detalles de implementación de foo.

Esto lleva a una menor flexibilidad: no se puede cambiar el tipo de tiempo de ejecución de foo con ninguna clase que implemente la interfaz GeneralFoo; solo puede inyectar instancias que implementen el descendiente AbstractFoo, dejándolo con un subconjunto más pequeño.

Lo ideal sería que las clases como UsesFoo solo conozcan las interfaces de los colaboradores que utilizan, y no los detalles de implementación.

Y, por supuesto, si no hay necesidad de declarar nada abstract en un abstract class AbstractFoo implements GeneralFoo - es decir, sin aplicación común que serán reutilizar todas las subclases - entonces esto es simplemente una pérdida de un archivo extra y los niveles de la jerarquía.

4

Para mí "que no estaba acostumbrada a" no es razón suficiente. Pídale que explique sobre eso.

personal que haría uso de su solución, porque:

  1. AbstractFoo es redundante y anuncios ningún valor en la situación actual.

  2. Aunque se necesitó AbstractFoo (para algunas funcionalidades adicionales), siempre usaba el tipo más bajo que necesitaba: si GeneralFoo era suficiente, entonces usaría eso, no alguna clase derivada de él.

2

No hay daño al usar directamente una interfaz en el código. Si lo hubiera, Java no tendría interfaces.

Las desventajas de usar una interfaz directamente incluyen no poder alcanzar y los métodos específicos de clase que no se implementan en la interfaz. Para interfaces mal escritas, o clases que agregan mucha "otra" funcionalidad, esto es indeseable ya que se pierde la capacidad de acceder a los métodos necesarios. Sin embargo, en algunos casos esto podría ser un reflejo de una mala elección de diseño al crear la interfaz. Sin detalles, es muy difícil de saber.

Las desventajas de usar la clase base directamente incluyen ignorar eventualmente la interfaz ya que no se usa con frecuencia. En casos extremos, la interfaz se convierte en el código equivalente de un apéndice humano; "presente pero proporcionando poca o ninguna funcionalidad". Las interfaces no utilizadas probablemente no se actualizarán, ya que todos usarán directamente la clase abstracta base de todos modos. Esto permite que su diseño se pudra silenciosamente desde el punto de vista de cualquiera que realmente intente usar la interfaz. En casos extremos, no es posible manejar una clase extendida a través de la interfaz para realizar alguna funcionalidad crítica.

Personalmente, soy partidario de devolver clases a través de su interfaz y almacenarlas internamente en miembros a través de su subclase más baja. Esto proporciona un conocimiento íntimo de la clase dentro de la encapsulación de la clase, obliga a las personas a usar la interfaz (manteniéndola actualizada) externamente, y la encapsulación de la clase permite un posible reemplazo futuro sin demasiado alboroto.

2

Tengo curiosidad por si hay una ventaja al segundo estilo, o desventaja para el primer estilo, que me falta

que las razones para la primera interfaces estilo:

  1. A menudo, el diseño es tal que la interfaz es la interfaz pública del concepto, mientras que la clase abstracta es un detalle de implementación del concepto. Por ejemplo, considere List y AbstractList en el marco de recopilación. List es lo que suelen pedir los clientes; menos gente sabe acerca de AbstractList porque es un detalle de implementación para ayudar a los proveedores (implementadores) de la interfaz), no a los clientes (usuarios) de la clase.

  2. La interfaz es un acoplamiento más flexible, por lo tanto más flexible para admitir cambios futuros.

  3. Utilice el que más claramente representa el requisito de la clase, que a menudo es la interfaz. Por ejemplo, List se usa con frecuencia en lugar de AbsrtactList o ArrayList.Usando la interfaz, puede ser más claro para un futuro mantenedor que esta clase necesita algún tipo de List, pero no necesita específicamente un AbstractList o un ArrayList. Si esta clase se basó en alguna propiedad específica de AbstractList, es decir, necesita utilizar un método AbstractList, entonces usar AbstractList list = ... en lugar de puede ser una pista de que este código se basa en algo específico de AbstractList.

  4. Puede simplificar las pruebas/burlas para utilizar la interfaz más pequeña y más abstracta en lugar de utilizar la clase abstracta.

0

En primer lugar utilizo abundantemente las clases abstractas y de interfaz.

Creo que necesita ver valor en el uso de una interfaz antes de usarla. Creo que el enfoque de diseño es, oh, tenemos una clase, por lo tanto, deberíamos tener una clase abstracta y, por lo tanto, deberíamos tener interfaces.

En primer lugar, ¿por qué necesita una interfaz? En segundo lugar, ¿por qué tiene una clase abstracta? Parece que ella puede estar agregando cosas, por agregar cosas buenas. Debe haber un valor claro en la solución; de lo contrario, está hablando de un código que no tiene valor.

Emperically there debería ver el valor en su solución. Si no hay ningún valor, la solución es incorrecta, si no puede explicarse, no comprende por qué lo está haciendo.

El código simple es la mejor solución y refactorizador cuando necesita la complejidad, flexibilidad o el valor percibido que está obteniendo de la solución.

¡Muestra el valor o elimina el código!

Una cosa más, eche un vistazo al código de la biblioteca Java. ¿Utiliza eso el patrón abstracto/interfaz que ella está aplicando ... NO!

Cuestiones relacionadas