2008-09-29 13 views
66

PMD informaría una violación para:¿Por qué debería preferirse la interfaz para una clase Java?

ArrayList<Object> list = new ArrayList<Object>(); 

La violación era "Evitar el uso de tipos de implementación como 'ArrayList', el uso de la interfaz en lugar".

La siguiente línea corregiría la violación:

List<Object> list = new ArrayList<Object>(); 

¿Por qué este último con List usarse en lugar de ArrayList?

+0

Ver también http: // stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface – Raedwald

Respuesta

73

El uso de interfaces sobre tipos de hormigón es la clave para una buena encapsulación y para un acoplamiento flexible de su código.

Incluso es una buena idea seguir esta práctica al escribir sus propias API. Si lo hace, más adelante descubrirá que es más fácil agregar pruebas unitarias a su código (usando técnicas de burla), y cambiar la implementación subyacente si es necesario en el futuro.

Aquí hay un good article sobre el tema.

Espero que ayude!

27

Esto se prefiere porque desacopla el código de la implementación de la lista. El uso de la interfaz le permite cambiar fácilmente la implementación, ArrayList en este caso, a otra implementación de la lista sin cambiar el resto del código, siempre que solo use los métodos definidos en la Lista.

5

ArrayList y LinkedList son dos implementaciones de una lista, que es una colección ordenada de elementos. En lo que respecta a la lógica, no importa si utiliza una ArrayList o una LinkedList, por lo que no debe restringir el tipo para que sea eso.

Esto contrasta con, por ejemplo, Colección y Lista, que son cosas diferentes (La lista implica clasificación, Colección no).

0

En general, para su línea de código no tiene sentido molestarse con las interfaces. Pero, si hablamos de API, hay una buena razón. Tengo pequeña clase

class Counter { 
    static int sizeOf(List<?> items) { 
     return items.size(); 
    } 
} 

En este caso es el uso de la interfaz requerida. Porque quiero contar el tamaño de cada posible implementación de, incluida la mía. class MyList extends AbstractList<String>....

+0

Si codifica implementaciones como ArrayList, existe la posibilidad de que utilice métodos de implementación incluso cuando podría hacer lo mismo cosa con métodos de interfaz. Esto vincularía su código a la implementación, dificultando el cambio entre implementaciones más adelante. – Champ

1

Las propiedades de sus clases/interfaces deben exponerse a través de las interfaces, ya que le da a sus clases un contrato de comportamiento para usar, independientemente de la implementación.

Sin embargo ...

En declaraciones de variables locales, no tiene mucho sentido hacer esto:

public void someMethod() { 
List theList = new ArrayList(); 
//do stuff with the list 
} 

Si es una variable local, sólo tiene que utilizar el tipo. Todavía es implícitamente upcastable a su interfaz apropiada, y sus métodos deberían aceptar los tipos de interfaz para sus argumentos, pero para las variables locales, tiene mucho sentido usar el tipo de implementación como contenedor, en caso de que necesite la implementación. funcionalidad específica.

10

En general, estoy de acuerdo en que la interfaz de desacoplamiento de la implementación es una buena cosa y hará que su código sea más fácil de mantener.

Existen, sin embargo, excepciones que debe tener en cuenta. El acceso a objetos a través de interfaces agrega una capa adicional de direccionamiento indirecto que hará que su código sea más lento.

Para mayor interés, ejecuté un experimento que generó diez mil millones de accesos secuenciales a una ArrayList de 1 millón de longitud. En mi MacBook de 2.4Ghz, el acceso a ArrayList a través de una interfaz de lista tomó 2,10 segundos en promedio, cuando se declaró de tipo ArrayList tomó en promedio 1,67 segundos.

Si está trabajando con listas grandes, en el interior de un bucle interno o con frecuencia se llama función, esto es algo que debe tener en cuenta.

+0

@Owen: +5 Insightful re: Diferencia de rendimiento ... Muy inesperado –

+2

Sin embargo, esta respuesta muestra que la sobrecarga puede ser muy pequeña: http://stackoverflow.com/questions/890687/overhead-of-implementing-an-interface/891096 # 891096 – Raedwald

+1

¡Guau! 0.5 segundos para diez mil millones de accesos, es decir, ¡1 acceso a la interfaz es medio nanosegundo más lento que un acceso de clase! Esta es, por supuesto, una razón para nunca, nunca usar interfaces. – Ingo

1

Incluso para variables locales, el uso de la interfaz sobre la clase concreta ayuda. Puede terminar llamando a un método que está fuera de la interfaz y luego es difícil cambiar la implementación de la Lista si es necesario. Además, es mejor usar la clase o interfaz menos específica en una declaración. Si el orden de los elementos no tiene importancia, use una Colección en lugar de una Lista. Eso le da a su código la máxima flexibilidad.

0

marco de Primavera se aplica el concepto de interfaces muy bien - http://www.springframework.org/

primavera suministra la aplicación a una clase concreta a través de archivo de configuración y por lo que la clase concreta no necesita saber nada acerca de la implementación.

Study of Spring ejemplifica las ventajas de la programación basada en interfaz en Java.

1

¿Por qué se debe usar el último con List en lugar de ArrayList?

Es una buena práctica: Programa de interfaz en lugar de aplicación

Al reemplazar ArrayList con List, puede cambiar List aplicación en el futuro de la siguiente manera dependiendo de su caso el uso del negocio.

List<Object> list = new LinkedList<Object>(); 
/* Doubly-linked list implementation of the List and Deque interfaces. 
Implements all optional list operations, and permits all elements (including null).*/ 

O

List<Object> list = new CopyOnWriteArrayList<Object>(); 
/* A thread-safe variant of ArrayList in which all mutative operations 
(add, set, and so on) are implemented by making a fresh copy of the underlying array.*/ 

O

List<Object> list = new Stack<Object>(); 

/* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/ 

O

alguna otra List aplicación específica.

List interfaz define el contrato y la implementación específica de List se puede cambiar. De esta manera, la interfaz y la implementación de están ligeramente acopladas.

pregunta SE relacionadas:

What does it mean to "program to an interface"?

Cuestiones relacionadas