Sto sviluppando un codice che utilizza i farmaci generici e uno dei miei principi guida era renderlo utilizzabile per gli scenari futuri, e non solo per quelli di oggi. Tuttavia, diversi colleghi hanno dichiarato che avrei potuto scambiare la leggibilità per motivi di estensibilità. Volevo raccogliere un feedback sui possibili modi per risolvere questo problema.
Per essere precisi, ecco un'interfaccia che definisce una trasformazione: si inizia con una raccolta di elementi di origine e si applica la trasformazione a ciascun elemento, memorizzando i risultati in una raccolta di destinazione. Inoltre, voglio essere in grado di restituire la raccolta di destinazione al chiamante e, anziché costringerli a utilizzare un riferimento alla raccolta, voglio che siano in grado di utilizzare qualsiasi tipo di raccolta effettivamente fornito per la raccolta di destinazione.
Infine, ho reso possibile che il tipo di elementi nella collezione di destinazione sia diverso dal tipo di elementi nella raccolta di origine, perché forse è ciò che fa la trasformazione. Nel mio codice, ad esempio, diversi elementi di origine costituiscono un elemento di destinazione dopo la trasformazione.
Questo produce la seguente interfaccia:
interface Transform<Src, Dst> {
<DstColl extends Collection<? super Dst>> DstColl transform(
Collection<? extends Src> sourceCollection,
DstColl destinationCollection);
}
Ho cercato di essere tutto gentile e applicare il principio PECS di Josh Bloch (produttore extends, consumer super) per assicurarmi che l'interfaccia sia utilizzabile con super- e sottotipi dove appropriato. Il risultato finale è in qualche modo una mostruosità.
Ora, sarebbe stato bello poter estendere questa interfaccia e specializzarla in qualche modo. Ad esempio, se non mi interessa davvero giocare bene con i sottotipi degli elementi sorgente e dei supertipi degli elementi di destinazione, potrei avere:
interface SimpleTransform<Src, Dst> {
<DstColl extends Collection<Dst>> DstColl transform(
Collection<Src> sourceCollection,
DstColl destinationCollection);
}
Ma non c'è modo di farlo in Java. Voglio rendere le implementazioni di questa interfaccia qualcosa che altri in realtà considererebbero di fare, invece di correre nella paura. Ho preso in considerazione diverse opzioni:
- Non restituire la raccolta di destinazione. Sembra strano dato che fai una trasformazione ma non ottieni niente indietro.
- Avere una classe astratta che implementa questa interfaccia, ma poi traduce i parametri in qualcosa di più facile da usare e chiama un altro metodo "translateImpl ()" che ha la firma più semplice e quindi presenta meno oneri cognitivi per gli implementatori. Ma è strano dover scrivere una classe astratta solo per rendere l'interfaccia user-friendly.
- rinunciare all'estensibilità e basta avere l'interfaccia più semplice. Forse coppia che non restituisce la collezione di destinazione. Ma questo limita le mie opzioni in futuro.
Che ne pensi? Mi manca un approccio che potrei usare?