È buona pratica racchiudere la raccolta in Java? [chiuso]

0

Mi sono imbattuto in uno snippet come questo, e ho scoperto che è finita l'ingegneria. È una buona pratica?

public class SchoolList extends ArrayList<School> {
}

public class School extends ArrayList<StudentList> {
}

public class StudentList extends ArrayList<Student> {
}

public class Student {
}

In realtà preferisco una semplice opzione:

List<List<List<Student>>> schoolList;
    
posta Truong Ha 28.02.2014 - 08:30
fonte

5 risposte

7

Di solito, usi semplicemente l'API JDK esistente. Perché? Lascia che ti dia un feedback sul tuo codice:

public class School extends ArrayList<StudentList> {
}

o, in altre parole: una scuola IS-Un elenco di liste di studenti (elenco di gruppi / classi?). Che cos'è veramente una scuola?

Una scuola è un'istituzione. Puoi trovare studenti all'interno (HAS-A), stanze, proffesors e altro ancora. Ovviamente, se vuoi riprogettare il codice di cui sopra, finirai per scrivere:

public class School {
  private List<Student> students; // or list of list? your choice
}

Inoltre, se si osservano i metodi pubblici, si avrà un metodo addAll, con Collection<StudentList> come argomento. Una scuola IS-Un elenco di StudentList (la tua implementazione), così puoi farlo:

School s1 = ...;
School s2 = ...;
s1.addAll(s2);

Trovate il codice sopra logico? Semplicemente non riesco a immaginare una scuola che aggiunge un'altra scuola :) Il metodo addStudents sembra più appropriato, come questo:

s1.addStudents(s2.getStudents());

Questa linea parla da sola: gli studenti andranno in un'altra scuola il prossimo anno:)

Dovresti estendere / implementare le classi / interfacce attuali solo quando ritieni che non sia adatto a te. Immagina una lista circolare, l'iteratore dovrebbe spostarsi sul primo elemento alla fine dell'elenco. Non conosco alcuna implementazione di elenchi circolari nell'API JDK, sono costretto a implementare la mia, non ho altra scelta. Hai.

    
risposta data 28.02.2014 - 09:27
fonte
5

È una buona pratica sostituire qualcosa come List<List<Map<String, Integer>>> con una classe specifica di dominio. Ma in quasi tutti i casi il modo migliore per farlo è l'aggregazione, non l'ereditarietà. Questo ha alcuni vantaggi:

  • nessun accoppiamento stretto con la superclasse
  • puoi scegliere quali metodi esporre; potresti non voler utilizzare tutti i metodi di ArrayList
  • non si viola l'incapsulamento

In generale non va bene estendere le raccolte; se vuoi avere la funzionalità List , dovresti comunque utilizzare l'aggregazione per la funzionalità e implementare l'interfaccia List . Per maggiori dettagli su questo vedi l'articolo 16 in Edizione Java efficace 2a di Joshua Bloch.

Nel tuo caso, invece di

public class School extends ArrayList<Student> {
}

utilizzo

public class School {
    private List<Student> list;
}

o se hai bisogno della funzionalità List :

public class SchoolList implements List<Student> {
     private List<Student> list;
}
    
risposta data 28.02.2014 - 09:39
fonte
2

L'estensione di contenitori generici di solito non ha senso per tutto ciò che rappresenta un oggetto di business.

public class School extends ArrayList<Student>

In questo esempio, una scuola è un ArrayList di Student s. Ma è tutto una scuola? Che cosa fai quando i requisiti aziendali richiedono che la scuola riceva più attributi, come ArrayList<Teacher> o ArrayList<ClassRoom> ?

È molto meglio quando le classi non estendono il contenitore che rappresenta i loro dati. Invece di ciò, le classi dovrebbero essere compositi contenenti i contenitori che contengono i loro dati:

public class School {
     private List students;
     private List teachers;
     private List rooms;

     // methods for accessing and manipulating the above lists
}

Ma ci sono casi in cui estendere le raccolte ha senso? Sì, lo fa, quando vuoi un contenitore più avanzato. C'è stata una volta in cui avevo bisogno di una mappa che fosse in grado di dire quali modifiche sono state apportate. Così ho creato un public class LoggingHashMap extends HashMap<Object, Object> che sostituiva tutti i metodi dei mutatori per creare anche una voce in un giornale privato e aveva anche un metodo per recuperare e reimpostare quel giornale.

    
risposta data 28.02.2014 - 09:36
fonte
0

È potrebbe essere una buona pratica, ma solo se c'è qualcosa che il nuovo tipo può fare che il tipo generico non può fare.

Senza contesto, sembra che qualcuno abbia imparato una costruzione che era necessaria prima che i tipi generici venissero inventati e ora continua a utilizzarlo anche se non è più necessario. Dopotutto, l'accesso sicuro alla raccolta è praticamente il motivo per cui Generics è stato inventato in primo luogo!

Ma potrebbero esserci casi d'angolo e usi speciali in cui il extends ha effettivamente un senso. Ad esempio, può essere complicato passare una variabile tipicamente generica a un metodo che si aspetta parametri vararg. Se il problema si verifica effettivamente, avere un tipo definito per oggetti comuni nel modello di dominio potrebbe fornire un vantaggio di leggibilità che superi le definizioni aggiuntive.

    
risposta data 28.02.2014 - 09:08
fonte
0

Dipende. Se si desidera attribuire il comportamento del dominio a tali raccolte, o se non tutti i metodi di una Lista ordinaria avrebbero senso in quella raccolta, allora la considererei una buona pratica.
Se non altro, comunica molto bene l'intento, ma se questo è l'unico motivo per farlo, allora potresti obiettare che è troppo ingegnoso.

    
risposta data 28.02.2014 - 09:11
fonte