Sospetto che sia qualcosa che molti di voi hanno affrontato, e sono certo che ci sono articoli su come farlo, ma non riesco a trovarli.
Il mio problema è che le mie varie classi costanti in Java (leggi: le classi contenenti liste di valori costanti statici) sono troppe e troppo grandi, e alcune di esse hanno alcuni fastidiosi inizializzatori statici complessi.
Abbiamo una classe di percorsi di file, una classe di nomi di file, una classe di costanti, una classe di stringhe, una classe di colori (per i componenti di swing) e un mucchio di css per i componenti di JavaFX ... continua sopra. Il CSS è gestibile, il resto sta diventando rapidamente non così.
Avere classi come questa:
public class Constants {
public static final String something = "Something";
public static final Path someResourcePath = staticMethodCall(RootString, dirTraversal);
public static final Image spinner = iconFindingStaticMethod(dirTraversal)
//and on and on for hundreds (not yet thousands thankfully) of lines
//and then often we have
static{
//code that determines our environment and fudges some paths as appropriate
//sometimes we ask the class loader to find some things for us
//nothing too scary, but still, static initializers are never friendly.
}
}
va bene per una ragione molto potente: ogni programmatore java là fuori sa esattamente cosa fa questa classe e come funziona. Quelli con inizializzatori statici potrebbero essere un po 'confusi, ma per la maggior parte, quanto sopra è PO-Static-JO. Mi piace.
Ma introduce anche una serie di problemi. Proverò a elencare quelli che conosco qui:
- l'odore di codice più ovvio di tutti: queste classi si stanno moltiplicando e sono tutte fastidiosamente grandi. Ne abbiamo uno per le estensioni di file che contiene una dozzina di voci, incluse cose come
public static final String XMLFileExtension = "xml"
. Potrebbe essere un po 'troppo, ma non sono davvero disposto a criticare lo sviluppatore che l'ha scritto. Non sarebbe difficile sostituire i riferimenti con il valore stringa, ma mi piacerebbe incoraggiare questo tipo di codice, quindi mi sentirei stupido a farlo. Ma queste classi stanno diventando grandi e fastidiose. - l'uso di costanti statiche non è testabile. Questo di per sé non è troppo spesso un problema poiché i valori in quelle classi dovrebbero essere semplici, ma si trasformano in un problema quando fai qualcosa come
Constants.someFilePath.exists() ? a() : b()
(poiché non c'è modo di di intercettare quelexists()
call , da qualsiasi ambiente chiederemo al file system attuale se quel percorso esiste, che è un problema per i test.) Siamo in vizio, quindi mi piacerebbe molto iniettare questi valori come tutto il resto, quindi possono essere modificati dai nostri dispositivi con valori falso / stub / mock. - Introduce anche un problema di dipendenza. In questo momento abbiamo un paio di IntelliJ & Guice Modules (basi di codici semi-separati) sotto lo stesso repository git. Tutti usano i file costanti del nostro modulo originale, il che significa che tutti i moduli hanno una dipendenza con quel modulo, ma con costanti statiche qual è la soluzione? Copia incolla?
Alcune soluzioni che ho pensato:
- potremmo sfruttare il guice e semplicemente iniettare ogni singola costante necessaria con un parametro
@Named
. Questo risolve i problemi 2 e amp; 3, ma comporta il problema 1 poiché la logica di legame dovrebbe essere incredibilmente lunga e contenere una quantità enorme di registrazione duplicata, o impiegare una composizione piuttosto complessa. - potremmo utilizzare la rotta auto-generate-source-java-da-XML-o-JSON, che ho utilizzato con Android e credo che alcuni componenti C # su cui ho lavorato brevemente. Il passaggio extra nel processo di costruzione aggiunge un livello di complessità in un'area (ovvero: devops) che non è familiare a molti sviluppatori. È stato bello avere solo una grande tabella in Eclipse che contenga tutti i miei valori, ma la complessità aggiunta al processo di generazione è indesiderata. Inoltre, la logica di inizializzazione statica potrebbe non adattarsi a questo modello.
- mantieni il corso con Java, magari estrai un pacchetto vicino alla rotta chiamata "Ambiente" o "costanti" e poi dai a quel pacchetto un numero di classi costanti che possono ereditare altre classi con campi condivisi. Per quanto riguarda la testabilità, eseguiamo java inlining dei campi finali. Potremmo sostituire ogni campo con un semplice getter, ma questo rende un problema già verbosamente più verboso.
Non so davvero come voglio affrontarlo. Mi sono detto di lasciarlo diventare un problema per alcuni mesi, pensando che sarebbe emersa una sorta di soluzione. Non lo è, e sappiamo che abbiamo un grafico di dipendenza grossa, hacks attorno al test del codice con percorsi di file e grandi classi costanti.
Che tipo di soluzioni hai impiegato per gestire questi file? Sono eccessivamente preoccupato e quello che abbiamo ora è la soluzione migliore?