2010-07-07 16 views
32

Entiendo los principios de la codificación en las interfaces: desacoplar la implementación de la interfaz y permitir que las implementaciones de la interfaz se intercambien dentro y fuera.Siempre debe codificar a las interfaces en Java

¿Debo codificar a las interfaces para cada clase que escribo o es ese overkill? No quiero duplicar la cantidad de archivos fuente en un proyecto a menos que realmente valga la pena.

¿Qué factores puedo usar para decidir si codigo por interfaz o no?

+0

Consulte esta pregunta también: http://stackoverflow.com/questions/3036749/is -it-the-best-practice-to-extract-an-interface-for-every-class –

+0

Gracias. Eso es lo que buscaba después de – Tarski

Respuesta

28

En general estoy de acuerdo con las otras respuestas: use una interfaz cuando sepa o anticipe un cambio y/o una implementación diferente, o vaya a prueba.

Pero no siempre es fácil saber de antemano qué puede cambiar en el futuro, especialmente si no tiene tanta experiencia. Creo que la solución para ese problema es la refactorización: mantenerlo simple (= sin interfaz), siempre que no sea necesario. Cuando surja la necesidad, simplemente realice una refactorización de "Introducir/Extraer interfaz" (compatible con casi todos los IDEs decentes).

Cuando lo haces, extrae solo los métodos que realmente necesitan los llamadores. No tema extraer más de una interfaz por separado (si no todos los métodos extraídos son realmente coherentes).

Un conductor de la refactorización podría ser la prueba: si no se puede probar fácilmente algo con clases sólo tienen en cuenta la introducción de uno/alguna de las interfaces (s). Esto también le permitirá usar burlas, lo que puede simplificar enormemente las pruebas en muchos casos.

Editar: basado en el comentario de Tarski me he dado cuenta de una más importante escenario/ajuste a las declaraciones anteriores:
Si proporciona una API externa (para otros proyectos [sub], o realmente lo liberan "a la wild ") y luego el uso de interfaces en la API (excepto para las clases de valor simple) es casi siempre una buena idea.
Te permitirá cambiar la impl si lo deseas sin molestar al código del cliente. Tendrá un problema solo si también tiene que cambiar la interfaz. No romper la compatibilidad será muy complicado (si no imposible).

+0

excelente respuesta. Me he encontrado exactamente con esto: tenía una clase utilizada por múltiples proyectos de clientes y ahora necesito una interfaz para ofrecer una implementación alternativa. Podría usar la anulación pero no es tan clara. El problema es que luego necesito recompilar a todos los clientes existentes para usar la interfaz. Como dijiste, no sabía que necesitaba la interfaz cuando comencé – Tarski

+1

Tienes razón con la recompilación, tienes que hacerlo después de la refactorización, pero solo una vez. Después de eso, la implementación está muy bien desacoplada, por lo que puede cambiarla/agregar nuevas sin necesidad de volver a compilarla. –

+0

En cuanto a la edición, es posible que desee leer sobre: ​​http://martinfowler.com/bliki/PublishedInterface.html – michaelsnowden

9

No, cada clase no debe tener una interfaz. Es excesivo al cuadrado.

Utiliza una interfaz cuando necesita abstraer lo que se hace de cómo se hace, y está seguro de que la implementación puede cambiar.

Eche un vistazo a la API de colecciones java.util para ver un buen ejemplo. La interfaz de lista es una buena abstracción para la idea general de una lista, pero puede ver que hay muchas formas de implementarla: ArrayList, LinkedList, etc.

ACTUALIZACIÓN: ¿Y qué pasa con el caso en el que diseña un concreto clase, decida después de que tiene clientes que se necesita una interfaz, y luego rompe sus clientes al agregar una interfaz? Sí, eso es lo que sucede. ¿Cómo puedes saber lo que no sabes? Ningún software o metodología puede arreglar eso.

La buena noticia para usted es que extraer una interfaz de una clase concreta es una fácil refactorización para usted y para sus clientes. Los IDE manejan ese tipo de cosas rutinariamente. Usted y sus clientes deben aprovecharlos.

Yo diría que las capas, como los servicios y la persistencia, siempre deben tener interfaces. Cualquier cosa que pueda ser proxiada debe tener una interfaz. Si está haciendo Spring AOP, cualquier cosa que desee decorar con un aspecto debe tener una interfaz.

Los objetos de modelo o valor, como Persona o Dirección o Teléfono, no deberían tener una interfaz. Un objeto de valor inmutable no debe tener una interfaz.

El resto cae en áreas grises. Usa tu mejor juicio.

+2

¿Pero qué pasa si no sabes que vas a necesitar la abstracción? P.EJ. Codifica una clase sin una interfaz, sus clientes dependen de la clase, luego necesita otra implementación pero no puede extraer una interfaz sin romper la compatibilidad binaria. – Tarski

+0

^esto. Además, ¿realmente es tan difícil crear una interfaz y que una clase la implemente? ¿Realmente toma mucho más tiempo simplemente hacerlo? – GreenieMeanie

11

lo uso cuando al menos uno de lo siguiente es cierto:

1) Quiero desacoplar módulos no relacionados/clases entre sí, y yo quiero que se refleja en las dependencias del paquete java.

2) Cuando la disociación es importante en términos de dependencias de construcción

3) Cuando la ejecución puede cambiar a través de la configuración o de forma dinámica en tiempo de ejecución (por lo general debido a algún patrón de diseño)

4) Cuando quiero una clase para ser verificable, hago sus "puntos de enlace" a las interfaces de recursos externos, de modo que pueda usar implementaciones simuladas.

5) Menos comunes: cuando quiero tener una opción para restringir el acceso a alguna clase. En este caso, mi método devuelve una interfaz en lugar de la clase real, por lo que la persona que llama sabe que no espero que haga otras operaciones en el valor devuelto.

+0

+1 para prueba y restricción de acceso –

2

Para resumir, no.Usted es el creador de la aplicación, por lo que tiene una idea decente de lo que podría cambiar . Algunos de los libros de patrones de diseño se vuelven un poco locos, en mi opinión, ya que parece que siempre impulsan el diseño a las interfaces y no a la implementación, pase lo que pase. A veces, es exagerado. Para mi última aplicación (tamaño pequeño), tengo una interfaz de base de datos porque creo que hay una posibilidad de que más adelante lo transfiera a la web y cambie a MySQL. Por supuesto, en realidad, sería fácil crear una interfaz de base de datos en el camino de mi clase existente y simplemente agregar "implementa myDbInterface" más tarde con un par de pequeños cambios. Esto funciona porque yo soy el único desarrollador. En un equipo más grande, o en un tipo diferente de producto, puede ser una respuesta diferente. Solo use su mejor criterio (después de leer todas las buenas respuestas de SO por supuesto).

1

Me gusta pensar que uno usa interfaces cuando la capacidad de conexión y la posibilidad de un comportamiento diferente es importante. Los servicios son el ajuste perfecto. Uno podría querer una implementación predeterminada, pero la falsificación (burla), etc. es otra. Esto obviamente significa que debe haber un intf ya que siempre habrá al menos 2 formas.

Los tipos de valor, por otro lado, deben ser clases finales. Nunca deberían extenderse. Los tipos de valor incluyen algo como suburbio, MimeType. Si hay variaciones de estos, usa la composición. Como objetivo, intento poner poco comportamiento, si hay alguno en mis tipos de valores. Validar el tipo simple que envuelve, etc. es probablemente lo más complejo que hace. Por ejemplo, una clase de color que toma r/g/b debería validar que cada componente está entre 0 y 255 y eso es todo.

0

Sí, utilice la interfaz cuando espera que cambie un comportamiento. . En el futuro.

O su clase que puede manejar los cambios de manera clara.

por ejemplo.

public static void main(String s[]) 
{ 
Employee e1=new Employee(new Salesman()); 
Employee e2=new Employee(new Manager()); 

system.out.println(e1.performaction()); 
system.out.println(e1.performaction()); 
} 

Class Employee 
{ 

//which changes frequently 
Authority a; 

public Employee(Authority a) 
{ 
this.a=a; 
}  
public String performAction() 
{ 
a.action(); 
} 
} 

// ----------------------------------------- -------------------------

interface Authority 
{ 
public String action(); 
} 

class Manager implements Authority 
{ 
public String action() 
{ 
returns "I manages People"; 
} 

class SalesMan implements Authority 
{ 
    public String action() 
{ 
returns "I Sell things Company makes "; 
} 
} 
Cuestiones relacionadas