Domanda

PMD segnalerebbe una violazione per:

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

La violazione era " Evitare l'uso di tipi di implementazione come 'ArrayList'; usa invece l'interfaccia " ;.

La seguente riga correggerebbe la violazione:

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

Perché utilizzare quest'ultimo con List anziché ArrayList?

È stato utile?

Soluzione

L'uso di interfacce su tipi concreti è la chiave per un buon incapsulamento e per un accoppiamento non corretto del codice.

È anche una buona idea seguire questa pratica quando si scrivono le proprie API. Se lo fai, scoprirai in seguito che è più semplice aggiungere test unitari al tuo codice (usando tecniche di derisione) e, se necessario, modificare l'implementazione sottostante in futuro.

Ecco un buon articolo sul soggetto.

Spero che sia d'aiuto!

Altri suggerimenti

Questo è preferito perché si disaccoppia il codice dall'implementazione dell'elenco. L'uso dell'interfaccia consente di modificare facilmente l'implementazione, in questo caso ArrayList, in un'altra implementazione dell'elenco senza modificare il resto del codice purché utilizzi solo i metodi definiti in Elenco.

In generale, sono d'accordo sul fatto che il disaccoppiamento dell'interfaccia dall'implementazione sia una buona cosa e faciliterà la manutenzione del codice.

Vi sono, tuttavia, delle eccezioni che è necessario considerare. L'accesso agli oggetti tramite interfacce aggiunge un ulteriore livello di riferimento indiretto che rallenta il codice.

Per interesse ho condotto un esperimento che ha generato dieci miliardi di accessi sequenziali a una matrice di 1 milione di lunghezza. Sul mio MacBook da 2,4 Ghz, l'accesso all'ArrayList tramite un'interfaccia Elenco ha richiesto in media 2,10 secondi, mentre per dichiararlo di tipo ArrayList sono stati necessari in media 1,67 secondi.

Se stai lavorando con elenchi di grandi dimensioni, all'interno di un ciclo interno o spesso chiamati funzione, allora questo è qualcosa da considerare.

ArrayList e LinkedList sono due implementazioni di un elenco, che è una raccolta ordinata di elementi. Dal punto di vista logico, non importa se usi un ArrayList o un LinkedList, quindi non dovresti vincolare il tipo a quello.

Questo contrasta con diciamo, Collection and List, che sono cose diverse (List implica l'ordinamento, la Collection no).

  

Perché usare quest'ultimo con List al posto di ArrayList?

È una buona pratica: Programma di interfaccia anziché implementazione

Sostituendo ArrayList con List, puoi cambiare <=> l'implementazione in futuro come di seguito a seconda del tuo caso d'uso aziendale.

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

qualche altra <=> implementazione specifica.

L'interfaccia

<=> definisce il contratto e l'implementazione specifica di <=> può essere modificata. In questo modo, l'interfaccia e l'implementazione sono vagamente accoppiate.

Domanda SE relativa:

Cosa significa " programma a un'interfaccia " ;?

Anche per le variabili locali, l'uso dell'interfaccia sulla classe concreta aiuta. Potresti finire per chiamare un metodo esterno all'interfaccia e, se necessario, è difficile modificare l'implementazione dell'elenco. Inoltre, è meglio utilizzare la classe o l'interfaccia meno specifica in una dichiarazione. Se l'ordine degli elementi non ha importanza, utilizzare una raccolta anziché un elenco. Ciò offre al tuo codice la massima flessibilità.

Le proprietà delle tue classi / interfacce dovrebbero essere esposte attraverso le interfacce perché danno alle tue classi un contratto di comportamento da usare, indipendentemente dall'implementazione.

Tuttavia ...

Nelle dichiarazioni delle variabili locali, ha poco senso farlo:

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

Se è una variabile locale, basta usare il tipo. È ancora implicitamente aggiornabile alla sua interfaccia appropriata, e si spera che i tuoi metodi dovrebbero accettare i tipi di interfaccia per i suoi argomenti, ma per le variabili locali, ha perfettamente senso usare il tipo di implementazione come contenitore, nel caso in cui tu abbia bisogno dell'implementazione- funzionalità specifica.

In generale per la tua riga di codice non ha senso preoccuparsi delle interfacce. Ma, se stiamo parlando di API, c'è davvero una buona ragione. Ho preso una piccola classe

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

In questo caso è richiesto l'uso dell'interfaccia. Perché voglio contare la dimensione di ogni possibile implementazione compresa la mia personale. class MyList extends AbstractList<String>....

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top