Parte del problema qui è che Java non ha alias di tipo. A volte la sottoclasse viene utilizzata per introdurre un nome abbreviato per un tipo complesso, ma non è lo stesso. Letteralmente - hai introdotto un nuovo tipo. Mentre l'uso di questa sottoclasse va bene per le variabili locali, non è adatto per le interfacce pubbliche (ad esempio le firme dei metodi).
Oltre a questo problema, considera se valga la pena di un'astrazione. L'obiettivo di un'astrazione è nascondere alcuni dettagli. Usare l'astrazione dovrebbe essere più facile che dover capire tutti i dettagli. Ma prima dobbiamo capire l'astrazione, quindi questo aggiunge anche dei costi. Se un'astrazione causa uno sforzo maggiore di quello che salva, non ne vale la pena.
Per le tue raccolte incartate, ogni programmatore Java sa cos'è una HashMap. Nessuno sa cos'è un CustomerMap, quindi dobbiamo prima saperlo. Ok, qui è solo una HashMap con chiavi Integer e valori Customer. L'ironia è, questa non è nemmeno un'astrazione - nessun dettaglio è davvero nascosto. Sì, il nome è abbreviato, ma a livello semantico tutti i dettagli sono ancora lì. Pertanto concordo sul fatto che questa astrazione non ne valga la pena e che il tuo codice potrebbe essere più facile da leggere se si scrive il tipo completo.
C'è un'alternativa: sviluppare una vera astrazione che fornisce funzionalità nel dominio del problema e nasconde dettagli non importanti. Un dettaglio potrebbe essere: utilizza internamente una HashMap.
es. considera questo design:
public final class Customers implements Iterable<Customer> {
private final HashMap<Integer, Customer> storedCustomers = new HashMap<>();
public void addCustomer(Customer customer) {
storedCustomers.put(customer.id, customer);
}
public Customer getCustomerById(int id) {
return storedCustomers.get(id);
}
public Iterator<Customer> iterator() {
return storedCustomers.values().iterator();
}
}
Gli utenti di questa classe devono capire molto meno degli utenti di una HashMap, quindi questa astrazione ~ potrebbe valerne la pena. Questo sarà più chiaramente il caso di MovieAgeRangeMap perché l'astrazione potrebbe gestire la creazione dell'EnumMap nidificato, proteggendo così l'utente da questa complessità.
Quindi, di nuovo, se un'astrazione viene utilizzata solo in un punto, probabilmente non ne vale la pena perché non risparmia così tanto tempo nella comprensione del codice. In ogni caso devi bilanciare le varie forze sul tuo progetto quando cerchi di semplificare il codice. Ad esempio:
-
Coesione: i componenti più piccoli sono più facili da capire I componenti meno di VERSUS sono più facili da capire
o frasi al contrario: troppo codice in un posto è difficile da capire VERSUS troppi riferimenti esterni sono difficili da capire
-
Sviluppo: astrazioni salvataggio dello sforzo tramite riutilizzo VERSUS creazione di astrazioni riusabili richiede sforzo
-
Overhead mentale: astrazioni salva la complessità estraendo più dettagli Astrazioni di VERSUS introduce la complessità introducendo un altro concetto che deve essere appreso prima
O estremo è male, ma il bilanciamento di questi fattori è difficile.
-
Le tue classi wrapper possono essere criticate perché risparmiano pochissima complessità ma introducono un altro concetto.
-
Il tuo alto numero di pacchetti / classi può essere criticato per lo stesso motivo: molti concetti che ciascuno aggiunge pochissimo valore. Per le classi modello questo è comprensibile perché rappresentano un concetto significativo. Ma questo è problematico se la funzionalità è distribuita su più pacchetti. Identificare le giunture lungo le quali la funzionalità dovrebbe essere suddivisa diventa più facile con l'esperienza. Se una classe è necessaria solo come dettaglio di implementazione di un'altra classe, potrebbe essere opportuno un private class
o una classe nidificata.