Inizializzazione delle proprietà che non sono parametri in un costruttore: alternative

3

Una classe carica le proprietà da un file e le usa mentre svolge i suoi compiti. A scopo di test, voglio essere in grado di modificare direttamente le proprietà senza dover utilizzare un file delle proprietà di test. Ho fatto l'implementazione, ma sembra piena di odori: sto lottando per mantenere questa cosa piccola (evitando strutture come Spring che avvolgono e iniettano le proprietà).

In particolare, non riesco a ricordare di aver visto un costruttore che si inizializza tramite un insieme di proprietà caricato staticamente - in particolare che imposta valori variabili da qualche parte oltre ai parametri passati.

Sto cercando argomenti a favore / contrari a questo approccio, e spero di trovare alcune alternative se questo è davvero poco cool come credo.

private static final String CONFIG_FILE_NAME = String.format("config-%s.properties",
        null != System.getProperty("JAVA_ENV") ? System.getProperty("JAVA_ENV") : "development");
static {
    PROPERTIES = new Properties();
    try {
        PROPERTIES.load(MyClass.class.getClassLoader().getResourceAsStream(CONFIG_FILE_NAME));
        if (PROPERTIES.keySet().size() < 1) {
            LOGGER.error(String.format("failed to load %s: no properties", CONFIG_FILE_NAME));
        }
    }
    catch (final IOException ie) {
        LOGGER.error(String.format("failed to load %s", CONFIG_FILE_NAME), ie);
    }
}

private String property1;
private String property2;

public MyClass() {
    property1 = PROPERTIES.getProperty("prop.1");
    property2 = PROPERTIES.getProperty("prop.2");
}

/* public accessors for property1 and property2 go here */
    
posta eebbesen 17.12.2013 - 16:07
fonte

1 risposta

4

Per cominciare, l'inizializzatore statico di una classe o interfaccia con nome non può generare un'eccezione controllata ( JLS 11.2.3. Controllo delle eccezioni ). Cioè, se la progettazione dell'applicazione comporta in qualche modo eccezioni controllate per vari problemi all'inizializzazione, gli inizializzatori statici non sono semplicemente un'opzione.

Dato lo snippet di codice, lo hai già notato: il blocco catch registra solo IOException senza rilanciarlo. Ma anche senza eccezioni controllate, questa è una pratica abbastanza problematica. Puoi testarlo aggiungendo il codice che rigenera l'eccezione di runtime dal blocco catch (che verrà compilato) e simulando l'assenza del file di configurazione.

Pensa a come si sentirebbe a coloro che gestiscono la tua applicazione quando ottengono registri che riportano un oscuro ExceptionInInitializerError per un errore di battitura di routine nel nome del file di configurazione.

Ancora un altro motivo per cui questa pratica non è conveniente si può trovare in JLS 12.4.1. Quando si verifica l'inizializzazione

...Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization...

Qui sopra significa che si rinuncia molto al controllo quando si verifica l'inizializzazione. Alcuni framework possono attivarlo quando non te lo aspetti. Se la memoria serve, nella mia pratica ciò accadeva una volta quando la registrazione non era ancora completamente inizializzata - mi creda, non è stato divertente indagare sul motivo per cui l'applicazione si arresta quando i file di registro sono vuoti.

L'ultimo, ma non meno importante, questo design è molto scomodo per i test unitari. Ogni volta che vorrai usare MyClass nei test unitari, dovresti assicurarti che 1) file di configurazione sia presente nel file system e 2) che sia pieno di valori e proprietà desiderati.

Confronta questo progetto con il costruttore che prende semplicemente Properties come parametro:

    MyClass(Properties properties) {
        this.properties = properties; // initialize field from constructor parameter
    }

Testare con una classe costruita come sopra è facile come diventa. Nessun problema con il filesystem, nessun problema con il riempimento del file con proprietà e valori desiderati, semplice codice Java. Crei l'oggetto Proprietà e lo riempia comunque vuoi, direttamente dal tuo codice di prova, ovunque si trovi, ogni volta che ti è comodo.

Riassumendo, ci sono molti motivi per cui non puoi ricordare di aver visto un costruttore che si inizializza tramite un insieme di proprietà staticamente caricato .

    
risposta data 17.12.2013 - 17:06
fonte

Leggi altre domande sui tag