Come si definisce una classe di costanti in Java?


90

Supponi di dover definire una classe che tutto ciò che fa è contenere costanti.

public static final String SOME_CONST = "SOME_VALUE";

Qual è il modo preferito per farlo?

  1. Interfaccia
  2. Classe astratta
  3. Classe finale

Quale dovrei usare e perché?


Chiarimenti ad alcune risposte:

Enumerazioni : non userò le enumerazioni, non enumererò nulla, ma raccolgo solo alcune costanti che non sono correlate tra loro in alcun modo.

Interfaccia : non imposterò nessuna classe come una che implementa l'interfaccia. Voglio solo utilizzare l'interfaccia per richiamare le costanti in questo modo: ISomeInterface.SOME_CONST.


C'è qualche discussione simile qui: stackoverflow.com/questions/320588/… . Vorrei utilizzare una classe finale con un costruttore privato in modo che non possa essere istanziato.
Dan Dyer,

2
Scusa ma "non userò enumerazioni" trasforma questa domanda in "qual è il modo migliore per fare qualcosa di stupido?"
cletus

Non sto dicendo che implementerai l'interfaccia. Ma non ha senso usare un'interfaccia per farlo. Quindi, vai con la classe finale
:)

Qual è il problema con Enum? Puoi sempre usarlo per raccogliere "alcune costanti che non sono in alcun modo correlate tra loro". Hmm?
gedevan

6
Concettualmente, un enum è una cattiva scelta se le costanti non sono correlate. Un enum rappresenta valori alternativi dello stesso tipo. Queste costanti non sono alternative e potrebbero non essere nemmeno dello stesso tipo (alcune potrebbero essere stringhe, alcune intere, ecc.)
Dan Dyer,

Risposte:


94

Usa una lezione finale. per semplicità puoi quindi utilizzare un'importazione statica per riutilizzare i tuoi valori in un'altra classe

public final class MyValues {
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

in un'altra classe:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}

4
Qual è il vantaggio di creare una classe separata qui? Anche se normalmente non considero l'API di Calendar come un buon esempio di progettazione, va bene in termini di "le costanti relative al calendario sono nella classe Calendar".
Jon Skeet

7
il vantaggio sta nel non duplicare il codice, nel caso in cui sia necessario riutilizzare le costanti in più di una classe. Immagino che tu possa facilmente vedere il vantaggio di questo.
user54579

2
Perché duplicheresti il ​​codice? Fai riferimento all'altra classe. Trovo relativamente raro che una costante stia davvero da sola.
Jon Skeet

14
Per una migliore leggibilità avrei anche un costruttore predefinito privato senza corpo (e un commento corrispondente).
Ran Biron

5
Risposta piuttosto vecchia e questo commento è probabilmente fuori luogo, ma VALUE1.equals(variable)lo userei perché evita l'NPE.
Aakash

38

Il tuo chiarimento afferma: "Non userò enumerazioni, non enumererò nulla, raccoglierò solo alcune costanti che non sono correlate tra loro in alcun modo".

Se le costanti non sono affatto correlate tra loro, perché vuoi raccoglierle insieme? Metti ogni costante nella classe a cui è più strettamente correlata.


2
Jon: sono correlati nel senso che appartengono tutti alla stessa funzionalità. Tuttavia, non sono un'enumerazione di nulla ... Non detengono la proprietà che un oggetto è "una di quelle cose".
Yuval Adam,

13
Va bene. In tal caso, inseriscili nella classe più vicina alla funzionalità a cui sono correlati.
Jon Skeet

28

I miei suggerimenti (in ordine decrescente di preferenza):

1) Non farlo . Crea le costanti nella classe effettiva in cui sono più rilevanti. Avere una classe / interfaccia "bag of constants" non sta seguendo le migliori pratiche OO.

Io e tutti gli altri ignoriamo il numero 1 di tanto in tanto. Se hai intenzione di farlo, allora:

2) classe finale con costruttore privato Questo almeno impedirà a chiunque di abusare del tuo "bagaglio di costanti" estendendolo / implementandolo per ottenere un facile accesso alle costanti. (So ​​che hai detto che non l'avresti fatto, ma questo non significa che qualcuno verrà dopo che non lo farai)

3) interfaccia Funzionerà, ma non è mia preferenza a menzionare l'eventuale abuso al punto 2.

In generale, solo perché queste sono costanti non significa che non dovresti ancora applicare loro i normali principi oo. Se nessuno tranne una classe si preoccupa di una costante, dovrebbe essere privato e in quella classe. Se solo ai test interessa una costante, dovrebbe essere in una classe di test, non nel codice di produzione. Se una costante è definita in più posizioni (non solo accidentalmente la stessa), eseguire il refactoring per eliminare la duplicazione. E così via - trattali come faresti con un metodo.


2
Il problema dell'1 è che a volte inserirai nel tuo codice alcune dipendenze in un'altra classe di livello solo per recuperare la costante.
amdev

Tutti i campi in un'interfaccia sono implicitamente pubblici, statici e finali
Kodebetter

@Kodebetter Ma le interfacce possono essere estese / implementate per aggiungere più campi.
Wit

12

Come osserva Joshua Bloch in Effective Java:

  • Le interfacce devono essere utilizzate solo per definire i tipi,
  • le classi astratte non impediscono l'istanziabilità (possono essere sottoclasse e suggeriscono persino che sono progettate per essere sottoclasse).

Puoi usare un Enum se tutte le tue costanti sono correlate (come i nomi dei pianeti), inserire i valori delle costanti nelle classi a cui sono correlati (se hai accesso ad essi), o utilizzare una classe di utilità non instanciabile (definire un costruttore predefinito privato) .

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

Quindi, come già affermato, puoi utilizzare le importazioni statiche per utilizzare le tue costanti.


7

Il mio metodo preferito è non farlo affatto. L'età delle costanti è praticamente morta quando Java 5 ha introdotto le enumerazioni typesafe. E anche prima di allora Josh Bloch ha pubblicato una versione (leggermente più prolissa) di quella, che ha funzionato su Java 1.4 (e precedenti).

A meno che non sia necessaria l'interoperabilità con un codice legacy, non c'è davvero alcun motivo per utilizzare più costanti String / integer denominate.


2
Buona risposta, un esempio sarebbe meglio.
amdev

3

Usa solo la lezione finale.

Se vuoi essere in grado di aggiungere altri valori usa una classe astratta.

Non ha molto senso usare un'interfaccia, si suppone che un'interfaccia specifichi un contratto. Vuoi solo dichiarare alcuni valori costanti.



3

enumvanno bene. IIRC, un elemento in Java effettivo (2a edizione) ha enumcostanti che enumerano le opzioni standard che implementano una [parola chiave Java] interfaceper qualsiasi valore.

La mia preferenza è quella di utilizzare una [parola chiave Java] interfacerispetto a una final classper le costanti. Ottieni implicitamente il file public static final. Alcune persone sosterranno che un interfaceconsente ai cattivi programmatori di implementarlo, ma i cattivi programmatori scriveranno codice che fa schifo qualunque cosa tu faccia.

Quale sembra migliore?

public final class SomeStuff {
     private SomeStuff() {
         throw new Error();
     }
     public static final String SOME_CONST = "Some value or another, I don't know.";
}

O:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}

ma i cattivi programmatori scriveranno codice che fa schifo qualunque cosa tu faccia. È solo così vero. Se puoi adottare misure per mitigare la cattiva programmazione o eliminarla del tutto, allora hai un po 'di responsabilità nel farlo; essere il più esplicito possibile. Un cattivo programmatore non può prolungare una lezione finale.
liltitus27

1
@ liltitus27 In una certa misura sono d'accordo. Ma vuoi davvero un codice brutto solo per impedire ai programmatori poveri di scrivere codice sbagliato? Il codice che producono sarà ancora senza speranza, ma ora il tuo codice è meno leggibile.
Tom Hawtin - tackline

1

Oppure 4. Inseriscili nella classe che contiene la logica che utilizza maggiormente le costanti

... scusa, non ho resistito ;-)


3
Questa non è una buona idea. Questo crea dipendenze tra classi che non dovrebbero averne.
Yuval Adam,

Perchè no? Direi che le classi che usano le stesse costanti hanno comunque una dipendenza ... E in qualche modo deve esserci una classe che è la più dipendente da queste costanti.
Simon Groenewolt

Se ci fosse solo una classe che usa le costanti, questo potrebbe avere senso.
Tom Hawtin - tackline

-1
  1. Uno degli svantaggi del costruttore privato è che l'esistenza del metodo non potrebbe mai essere testata.

  2. Enum per il concetto di natura buono da applicare in un tipo di dominio specifico, applicarlo a costanti decentralizzate non sembra abbastanza buono

Il concetto di Enum è "Le enumerazioni sono insiemi di elementi strettamente correlati".

  1. Estendere / implementare un'interfaccia costante è una cattiva pratica, è difficile pensare alla necessità di estendere una costante immutabile invece di fare riferimento direttamente ad essa.

  2. Se si applicano strumenti di qualità come SonarSource, ci sono regole che costringono gli sviluppatori a eliminare l'interfaccia costante, questa è una cosa imbarazzante poiché molti progetti godono dell'interfaccia costante e raramente vedono cose "estese" accadere su interfacce costanti


1
"Il costruttore privato è l'esistenza di un metodo che non potrebbe mai essere testato": non è vero. Se tu (o il tuo capo) siete davvero paranoici sul fatto che i rapporti di copertura del codice siano al 100%, puoi comunque testarlo usando la riflessione e assicurandoti che il costruttore generi un'eccezione. Ma, IMHO, questa è solo una formalità e non ha davvero bisogno di essere testata. Se a te (o al team) interessa solo ciò che è veramente importante, la copertura della linea al 100% non è necessaria.
L. Holanda
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.