Quando si definiscono le costanti, che è più importante? Più facile da trovare? O portata più ristretta?

2

Ad esempio, considera che ho costanti VOL_MIN e VOL_MAX, che sono utilizzate solo all'interno di 1 funzione:

public void setVolume(int val){
    final int VOL_MIN = 1;
    final int VOL_MAX = 10;
    val=Math.max(VOL_MIN,Math.min(val,VOL_MAX));
    //some other code
}

Originariamente penso che tutto dovrebbe essere accessibile solo quando ne ho bisogno, e VOL_MIN e VOL_MAX sono usati solo da setVolume (), quindi li ho inseriti nella funzione.

Ma dopo alcuni giorni, quando ho iniziato a dimenticare ciò che ho scritto, ho trovato difficile mantenere: devo cercare "10" per trovare dove sono definite le costanti, che funziona come se fossero numeri magici.

Quindi la mia domanda è: dovrebbe essere possibile limitare l'ambito delle costanti? O dovrei definirli in un posto facile da trovare come le costanti statiche di classe o all'interno di una singola classe AppConstant anche se posso accedervi quando non ho bisogno?

    
posta mmmaaa 09.03.2018 - 03:18
fonte

3 risposte

4

La mia preferenza cade nel mezzo: definisco le costanti all'interno della classe / modulo che le usa, ma in una posizione ovviamente statica o "di inizializzazione", non in un singolo metodo.

Perché non definisco le costanti nei metodi

Lavoro principalmente in JavaScript dove, in teoria, se si definisce la costante in un metodo, tale dichiarazione viene eseguita ogni volta che viene chiamato il metodo.

// Created when the module is loaded
const VOL_MIN = 1;

function setVolume(val) {
  // Created every time setVolume is called
  const VOL_MAX = 10;
  // ...
}

In pratica, probabilmente gli interpreti moderni cercano di aiutarlo, ma è bello esserne certi. In Java la situazione è probabilmente simile, ma secondo questa risposta % le variabili distatic final saranno sicuramente delineate dal compilatore bytecode (non dal compilatore JIT) che potrebbe essere un più motivo convincente per definire le costanti sulla classe, piuttosto che all'interno di un metodo. In un linguaggio compilato dipende dal compilatore, ma probabilmente sono ottimizzati ovunque vengano inseriti.

Da una prospettiva di gestione dello stile e del cambiamento, trovo che le costanti tendono ad essere legate alle regole o alla configurazione aziendale, e quindi in un progetto in crescita sono raramente limitate a un unico metodo a lungo. Supponiamo che il tuo metodo setVolume sia su una classe Radio . Concettualmente, il volume minimo e massimo è un problema di livello Radio e potrebbe essere necessario in seguito per il rendering dell'interfaccia utente, creando una sorta di dissolvenza lineare, ecc.

Perché non definisco le costanti in un file Constants

Oltre a non essere una grande strategia organizzativa, le costanti di dumping in un file Constants viola il principio che il codice che cambia insieme dovrebbe convivere. Pensaci in termini di dipendenze di compilazione: se hai un file Constants e cambi il valore di una costante, ogni classe del codice che utilizza una costante deve essere ricompilata. Se le tue costanti vivono nei moduli che le usano, ricompila solo il modulo interessato (e le sue dipendenze downstream). Su grandi progetti, decisioni come questa iniziano ad avere un grande impatto sui tempi di sviluppo.

    
risposta data 09.03.2018 - 08:20
fonte
2

La risposta a tale domanda è, come sempre, "dipende".

Se tali costanti vengono utilizzate solo da setVolume , quindi inserendole in tale funzione, si mantiene l'ambito il più stretto possibile e si minimizza qualsiasi accoppiamento. Il loro scopo è evidente, nonostante VOL_MIN non contenga quasi nessuna informazione su ciò che fa. Posso indovinare che si riferisce ad un volume minimo che la funzione accetterà.

Se le costanti sono fuori in un file di costanti globali, allora sono più facili da trovare. Ma poi non ho idea di cosa siano, o cosa potrebbero usarli (anche se gli IDE tendono ad aiutare con questi ultimi). VOL_MIN non ha più senso. Quindi, se si espande l'ambito, i nomi devono migliorare enormemente, per contenere tanto di: che tipo di volume (ad es. Litri o volume); la parola completa "minimo", non un'abbreviazione; e, se possibile, perché esiste questa limitazione.

Non sono d'accordo che questi sono numeri magici in tutto tranne il nome. La chiave è che hanno nomi, quindi hanno un contesto. 10 è solo un numero. MaximumSpeakerVolume contiene informazioni su quel numero.

Suggerirei di mantenere l'ambito di tutto il più stretto possibile, sempre. Ma se mantenere le costanti ti causa davvero dei problemi, allora espandi l'ambito. Non rendi la vita difficile per te solo perché provi il senso del dovere di seguire le linee guida. Sii pragmatico ed efficiente, oltre che essere "buona pratica" disciplinata.

    
risposta data 09.03.2018 - 07:51
fonte
1

La tua domanda ha molteplici aspetti. (BTW: presumo che il tuo codice sia Java, quindi la mia risposta copre alcuni aspetti tecnici specifici di quella lingua)

Chi ha bisogno di questi valori?

Ne hai bisogno nel metodo setVolume() . Ma è meglio comunicare i limiti di val a un potenziale utente, quindi non è sorpreso che setVolume(100) abbia lo stesso effetto di setVolume(10) . Dovresti farlo in un commento Javadoc e magari rendendo accessibili i valori limite. Quindi potrebbe essere sensato renderli public static final dei campi della tua classe.

Dove puoi dichiararli per diventare veramente costanti?

In Java, dichiarare una variabile final significa solo che, dopo l'inizializzazione, si promette di non modificarne il valore in seguito. È ancora una variabile da allocare nello stack, visibile nel debugger e così via (ovviamente, i compilatori e il motore di HotSpot sono abbastanza intelligenti, quindi forse saranno in grado di rilevare che VOL_MIN è solo pensato per essere un altro nome per un valore letterale 1 ).

Senza fare affidamento sulle ottimizzazioni del compilatore, posizionare una "costante" (una variabile final ) in un metodo significa che ogni volta che si immette il metodo, viene allocata una parola sullo stack, il valore iniziale viene calcolato (non in il tuo caso, in quanto è un intero letterale) e copiato nella parola stack. Quindi, usare una "costante" viene fornita con un (piccolo, a seconda del livello di ottimizzazione) penalizzazione delle prestazioni.

Al contrario, un campo finale statico (dichiarato al di fuori di qualsiasi metodo) viene inizializzato solo una volta durante il caricamento della classe, e la specifica della lingua consente al compilatore di sostituire gli usi del campo con il solo valore letterale. E per esperienza personale so che ciò accade. Quindi i campi static final non hanno una penalizzazione delle prestazioni rispetto ai letterali semplici.

Ambito di applicazione

Quindi, dov'è il posto dove dichiarare le tue costanti?

  • All'interno del metodo in cui vengono utilizzati, non diventano realmente costanti, ma probabilmente non noterai la differenza. Usalo se sei preoccupato del possibile scopo più stretto. Ma assicurati che non siano davvero utili per il mondo esterno.
  • Come private static final campi della tua classe, sono visibili a tutti i metodi all'interno della tua classe, quindi l'ambito è leggermente più grande. E diventano costanti reali senza una penalità di prestazioni rispetto all'uso dei valori come valori letterali.
  • Come public static final campi della tua classe, diventano visibili a tutti gli utenti della tua classe, quindi l'ambito è abbastanza aperto. Diventano costanti reali senza una penalità di prestazioni rispetto all'uso dei valori come valori letterali. Essere parte della tua classe mostra che queste costanti sono legate alle proprietà della tua classe.
  • Come public static final campi di una classe "costanti", sono visibili a tutti gli utenti, quindi l'ambito è abbastanza aperto. Diventano costanti reali senza una penalità di prestazioni rispetto all'uso dei valori come valori letterali. Essere in una classe non correlata al tuo metodo setVolume() rende difficile vedere la relazione con questo metodo.

Riepilogo

Se decidi che i valori non sono necessari al di fuori del metodo setVolume() , cercherò i campi private static final o (opinione personale), basta usare i valori letterali semplici (in un metodo così breve e semplice, I non vedo un vantaggio di leggibilità nell'introdurre i nomi).

Se decidi che i valori sono utili anche per gli utenti del metodo setVolume() , utilizzerei i campi public static final nella stessa classe.

Se i valori riguardano più metodi in più classi, inseriscili in una classe "costanti".

Qualunque cosa tu faccia, introdurre un nome per un valore letterale non dovrebbe togliere informazioni, quindi controlla le varie possibilità con il tuo IDE preferito per vedere se mostra il valore quando passa il mouse sopra i riferimenti della costante.

    
risposta data 09.03.2018 - 12:29
fonte

Leggi altre domande sui tag