Qual è l'uso delle costanti di interfaccia?


123

Sto imparando Java e ho appena scoperto che l'interfaccia può avere campi, che sono statici pubblici e finali. Finora non ne ho visto alcun esempio. Quali sono alcuni dei casi d'uso di queste costanti di interfaccia e posso vederne alcuni nella Java Standard Library?

Risposte:


190

Mettere membri statici in un'interfaccia (e implementare quell'interfaccia) è una cattiva pratica e c'è anche un nome per esso, Constant Interface Antipattern , vedi Effective Java , Item 17:

Il modello di interfaccia costante è un cattivo utilizzo delle interfacce . Che una classe utilizzi alcune costanti internamente è un dettaglio di implementazione. L'implementazione di un'interfaccia costante fa sì che questo dettaglio di implementazione trapeli nell'API esportata della classe. Non ha importanza per gli utenti di una classe che la classe implementa un'interfaccia costante. In effetti, potrebbe persino confonderli. Peggio ancora, rappresenta un impegno: se in una futura release la classe viene modificata in modo da non dover più utilizzare le costanti, deve comunque implementare l'interfaccia per garantire la compatibilità binaria. Se una classe non finale implementa un'interfaccia costante, tutte le sue sottoclassi avranno i loro spazi dei nomi inquinati dalle costanti nell'interfaccia.

Ci sono diverse interfacce costanti nelle librerie della piattaforma java, come java.io.ObjectStreamConstants. Queste interfacce dovrebbero essere considerate come anomalie e non dovrebbero essere emulate.

Per evitare alcune insidie ​​dell'interfaccia costante (perché non puoi impedire alle persone di implementarla), dovrebbe essere preferita una classe appropriata con un costruttore privato (esempio preso in prestito da Wikipedia ):

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

E per accedere alle costanti senza doverle qualificare completamente (cioè senza doverle anteporre al nome della classe), usa un'importazione statica (da Java 5):

import static Constants.PLANCK_CONSTANT;
import static Constants.PI;

public class Calculations {

    public double getReducedPlanckConstant() {
        return PLANCK_CONSTANT / (2 * PI);
    }
}

12
Ok, ma cosa succede se hai un'interfaccia che non è solo per la definizione costante. Quindi ho un'interfaccia implementata da molte classi che contiene dichiarazioni di metodi ma voglio anche aggiungere anche alcuni valori comuni come size, ad esempio. È davvero un cattivo schema in questo caso. In generale sono d'accordo che creare interfacce solo per le costanti è un antipattern.
Łukasz Rzeszotarski

11
Non è una brutta cosa solo perché qualcuno lo dice in un libro. Finché non si implementa quell'interfaccia per ottenere l'accesso a quelle costanti, va bene.
ACV

11
No No No. Quella citazione in Java efficace riguarda qualcos'altro! La creazione di interfacce solo costanti è un'alternativa migliore alle classi che contengono tali costanti. Java efficace dice: "Che una classe usi internamente alcune costanti è un dettaglio di implementazione". Ma qui non è così. Stiamo parlando di costanti "globali". E chi vorrebbe implementare un'interfaccia senza dichiarazioni di metodo in essa?
ACV

6
Sono d'accordo con ACV. Se l'interfaccia costante non fa parte del modulo API esportato o quando non è implementata da nessuna parte, non vedo il problema. Usare le classi finali const è brutto: è necessario un costruttore privato che ingombra il codice in quanto non serve.
Lawrence,

2
Questa risposta non presenta correttamente il punto principale del libro "Effective Java", perché "retrocede" il punto principale mettendolo tra parentesi: "(e implementando tale interfaccia)". Invece enfatizza il punto delle costanti nelle interfacce (che sono OK a meno che non si implementi una tale interfaccia). Non è una risposta generalmente cattiva, perché se leggi attentamente il frammento citato, puoi vedere cosa intendeva originariamente l'autore di "Effective Java". Ma lo trovo fuorviante. A mio parere la parte "e l'implementazione di tale interfaccia" dovrebbe essere in grassetto per enfatizzarla.
krm

17

" Il modello di interfaccia costante è un cattivo uso delle interfacce "

Chiunque abbia inventato questa ipotesi, per quanto un guru possa essere, l'ha inventata sulla base della necessità di continuare a mettere in atto le cattive abitudini e pratiche in modo efficiente. L'ipotesi si basa sulla promozione della validità di cattive abitudini di progettazione del software.

Ho scritto una risposta di confutazione contro questa ipotesi qui: Qual è il modo migliore per implementare le costanti in Java? spiegando l'infondatezza di questa ipotesi.

Per 10 anni quella domanda era rimasta aperta, fino a quando non è stata chiusa entro 2 ore dopo che ho postato le mie ragioni scoraggiando questa ipotesi, esponendo così la DIS VOLONTA 'al dibattito da parte di coloro che si aggrappano a questa ipotesi sbagliata a caro prezzo.

Questi sono i punti che ho espresso contro l'ipotesi

  • La base per sostenere questa ipotesi è la necessità di metodi e regole RESTRITTIVE per far fronte agli effetti delle cattive abitudini e metodologie del software.

  • I sostenitori del sentimento " Il modello di interfaccia costante è un cattivo uso delle interfacce" non sono in grado di fornire ragioni diverse da quelle causate dalla necessità di far fronte agli effetti di quelle cattive abitudini e pratiche.

  • Risolvi il problema fondamentale.

  • E allora perché non fare pieno uso e sfruttare ogni caratteristica del linguaggio della struttura del linguaggio Java a proprio piacimento. Nessuna giacca richiesta. Perché inventare regole per barricare il tuo stile di vita inefficace per discriminare e incriminare stili di vita più efficaci?

La questione fondamentale

è l'organizzazione dell'informazione. Le informazioni che mediano il processo e il comportamento di tali informazioni dovrebbero essere prima comprese, insieme alle cosiddette regole di business, prima di progettare o integrare soluzioni al processo. Questo metodo di organizzazione delle informazioni è stato chiamato normalizzazione dei dati alcuni decenni fa.

Quindi solo l'ingegnerizzazione di una soluzione sarà possibile perché allineare la granularità e la modularità dei componenti di una soluzione con la granularità e la modularità dei componenti delle informazioni è la strategia ottimale.

Ci sono due o tre ostacoli significativi all'organizzazione delle informazioni.

  1. La mancanza di percezione della necessità di "normalizzazione" del modello di dati.

  2. Le dichiarazioni di EF Codd sulla normalizzazione dei dati sono errate, difettose e ambigue.

  3. L'ultima moda mascherata da ingegneria agile è l'idea sbagliata che non si dovrebbe pianificare e condizionare l'organizzazione dei moduli in anticipo perché è possibile eseguire il refactoring man mano che si procede. Il refactoring e il cambiamento continuo senza essere ostacolato da scoperte future è usato come scusa. Le scoperte essenziali del comportamento delle informazioni di processo sono quindi, utilizzando trucchi contabili per ritardare i profitti e l'assetization, per cui le conoscenze essenziali e il loro trattamento sono ritenute non necessarie ora.

L'utilizzo delle costanti di interfaccia è una buona pratica.

Non inventare regole né emettere fatwa contro di esso solo perché ami le tue abitudini di programmazione ad hoc.

Non vietare la proprietà di armi con la ragione che ci sono persone che o non sanno come maneggiarle o sono inclini ad abusarne.

Se le regole che crei sono pensate per programmare i principianti incapaci di codificare professionalmente e che ti annoi tra di loro, allora dillo - non dichiarare la tua fatwa come applicabile a modelli di dati correttamente normalizzati.

Un ragionamento stupido: le interfacce non erano intese dagli sbandati del linguaggio Java per essere utilizzate in questo modo?

Non mi interessa quali fossero le intenzioni originali dei padri fondatori per la costituzione degli Stati Uniti. Non mi interessano le intenzioni non scritte non modificate. Mi interessa solo ciò che è letteralmente codificato nella Costituzione scritta e come posso sfruttarli per il funzionamento efficace della società.

Mi interessa solo ciò che le specifiche del linguaggio / piattaforma Java mi consentono e intendo sfruttarle al massimo per offrirmi un mezzo per esprimere le mie soluzioni software in modo efficiente ed efficace. Non sono necessarie giacche.

L'uso delle costanti Enum è in realtà una pratica orribile.

Richiede la scrittura di codice aggiuntivo per mappare il parametro al valore. Il fatto che i fondatori di Java non abbiano fornito la mappatura valore-parametro senza che tu abbia scritto che il codice di mappatura dimostra che le costanti Enum sono un uso non intenzionale del linguaggio Java.

Soprattutto dal momento che non sei incoraggiato a normalizzare e componentizzare i tuoi parametri, ci sarebbe una falsa impressione che i parametri mescolati in una borsa Enum appartengano alla stessa dimensione.

Le costanti sono contratto API

Non dimenticarlo. Se hai progettato e normalizzato il tuo modello di dati e include costanti, quelle costanti sono contratti. Se non hai normalizzato il tuo modello di dati, dovresti conformarti alle fatwa fornite su come praticare la codifica restrittiva per far fronte a quella cattiva abitudine.

Pertanto, le interfacce sono un modo perfetto per implementare il contratto di Constants.

Una strana presunzione: cosa succede se l'interfaccia viene inavvertitamente implementata.

Sì. Chiunque potrebbe inavvertitamente implementare qualsiasi interfaccia inavvertitamente. Niente ostacolerà questi programmatori involontari.

Progetta e normalizza il tuo modello di dati contro le perdite

Non inserire decreti restrittivi per proteggere presunte cattive pratiche che causano la fuoriuscita di parametri non contrattuali / vaganti nell'API. Risolvi il problema fondamentale, piuttosto che dare la colpa alle costanti dell'interfaccia.

Non usare un IDE è una cattiva pratica

Un programmatore normale ed EFFICACE non è lì per dimostrare quanto tempo può stare sott'acqua, quanto lontano potrebbe camminare in caso di caldo torrido o temporali umidi. Deve usare uno strumento efficiente come un'auto o un autobus o almeno una bicicletta per portarle al lavoro 10 miglia ogni giorno.

Non porre restrizioni agli altri programmatori solo perché hai un'ossessione esoterica di ascetismo con la programmazione senza IDE.

Un paio di framework sono progettati per aiutare i programmatori a continuare a praticare le cattive abitudini in modo efficiente.

OSGI è un tale framework. E così è anche il decreto contro le Costanti di Interfaccia.

Quindi la risposta conclusiva ...

Le costanti di interfaccia sono un modo efficace ed efficiente per inserire nel contratto componenti ben progettati e normalizzati di un modello di dati.

Anche le costanti di interfaccia in un'interfaccia privata dal nome appropriato annidate in un file di classe sono una buona pratica per raggruppare tutte le costanti private piuttosto che spargerle in tutto il file.


29
Tutti i tuoi punti potrebbero essere fatti senza scherzi, sarcasmo, emotività. Stackoverflow non è una piattaforma di blog.
tkruse

1
"Non mi interessa quali fossero le intenzioni originali dei padri fondatori per la Costituzione degli Stati Uniti. Non mi interessano le intenzioni non scritte non modificate. Mi interessa solo ciò che è letteralmente codificato nella Costituzione scritta e come posso sfruttarle per l'efficace funzionamento della società ". - questa non è una buona allegoria?
Blessed Geek

"Richiede la scrittura di codice aggiuntivo per mappare il parametro al valore. Il fatto che i fondatori di Java non abbiano fornito la mappatura del valore del parametro senza che tu abbia scritto che il codice di mappatura dimostra che le costanti Enum sono un uso non intenzionale del linguaggio Java." In quale altro modo potresti ottenere la mappatura del valore dei parametri senza scrivere codice aggiuntivo?
GabrielOshiro

Usa le costanti dell'interfaccia. ESATTAMENTE.
Blessed Geek

9

Mi sono imbattuto in questa vecchia domanda diverse volte e la risposta accettata mi confonde ancora. Dopo molte riflessioni, penso che questa domanda possa essere ulteriormente chiarita.

Perché usare Interface Constant?

Basta confrontarli:

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

vs

public interface Constants {

    double PI = 3.14159;
    double PLANCK_CONSTANT = 6.62606896e-34;
}

Stesso utilizzo. Molto meno codice.

Cattiva pratica?

Penso che la risposta di @Pascal Thivent abbia l'enfasi sbagliata, ecco la mia versione:

Mettere membri statici in un'interfaccia ( e implementare tale interfaccia ) è una cattiva pratica.

La citazione da Effective Java presuppone che l'interfaccia costante venga implementata da altri, cosa che penso non dovrebbe (e non accadrà).

Quando crei un'interfaccia costante chiamata qualcosa di simile Constants, non dovrebbe essere implementata da nessuno. (sebbene tecnicamente possibile, che è l'unico problema qui)

Non accadrà nella libreria standard

La libreria standard non può permettersi alcun possibile uso improprio del design, quindi non ne vedrai nessuno.

Tuttavia , per i progetti di tutti i giorni di sviluppatori normali, utilizzando l'interfaccia costanti è molto più facile perché non c'è bisogno di preoccuparsi static, final,empty constructor , ecc, e sarà non causa alcun problema di progettazione male. L'unico aspetto negativo a cui riesco a pensare è che ha ancora il nome di "interfaccia", ma niente di più.

Dibattito senza fine

Alla fine, penso che tutti stiano solo citando dai libri e dando opinioni e giustificazioni alle loro posizioni. Nessuna eccezione per me. Forse la decisione spetta ancora agli sviluppatori di ogni progetto. Vai avanti per usarlo se ti senti a tuo agio. Il meglio che possiamo fare è renderlo coerente durante tutto il progetto .


"Mettere membri statici in un'interfaccia (e implementare tale interfaccia) è una cattiva pratica". No, non è
Raining

Il modificatore publicpuò anche essere omesso poiché è un'interfaccia, rendendolo semplicemente double PI = 3.14159;Usage of Constants.PInon ha bisogno della classe che lo usa per implementare l' Constantsinterfaccia! Penso che l'approccio all'interfaccia sia molto più pulito in termini di utilizzo, IMHO
krozaine

@krozaine Aggiornato. Grazie del promemoria. Riferimento per chiunque abbia dei dubbi: "Tutti i valori costanti definiti in un'interfaccia sono implicitamente pubblici, statici e finali". - docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html
Nakamura

6

Joshua Bloch, "Effective Java - Programming Language Guide":

Il modello di interfaccia costante è un cattivo utilizzo delle interfacce. Che una classe utilizzi alcune costanti internamente è un dettaglio di implementazione. L'implementazione di un'interfaccia costante fa sì che questo dettaglio di implementazione trapeli nell'API esportata della classe. Non ha importanza per gli utenti di una classe che la classe implementa un'interfaccia costante. In effetti, potrebbe persino confonderli. Peggio ancora, rappresenta un impegno: se in una futura release la classe viene modificata in modo da non dover più utilizzare le costanti, dovrà comunque implementare l'interfaccia per garantire la compatibilità binaria. Se una classe non finale implementa un'interfaccia costante, tutte le sue sottoclassi avranno i loro spazi dei nomi inquinati dalle costanti nell'interfaccia.


Non hai aggiunto letteralmente nulla di valore che non fosse già stato detto.
Donal Fellows


2

Ci sono risposte molto ragionevoli.

Ma ho alcuni pensieri su questa domanda. (potrebbe essere sbagliato)

A mio parere, i campi in un'interfaccia, non dovrebbero essere costanti all'intero progetto, sono solo mezzi per l'interfaccia e le interfacce la estendono e le classi che implementano queste interfacce o hanno una stretta relazione con esse. Dovrebbero essere utilizzati entro un certo intervallo non globale.


In effetti, dovrebbero essere utilizzati all'interno di quelle classi di implementazione.
Piove il

2

Due punti sull'interfaccia:

  • Un'interfaccia descrive un sottoinsieme di ciò che può fare un oggetto che lo implementa. (Questa è l'intuizione)

  • Un'interfaccia descrive le costanti comuni seguite da oggetti che la implementano.

    • Queste costanti comuni devono essere conosciute dal client per saperne di più su questi oggetti.
    • Quindi Constants Interface è davvero controintuitiva per la definizione di costanti globali , poiché l'interfaccia è usata per descrivere alcuni oggetti , non tutti gli oggetti / nessun oggetto (considera il significato di globale ).

Quindi penso che se Constants Interface non viene utilizzata per le costanti globali , allora è accettabile:

  • Se queste costanti comuni hanno buoni nomi, consiglieranno all'implementatore di usarle (vedere il mio primo punto per l'esempio di seguito)
  • Se una classe desidera sincronizzarsi con quelle classi seguendo le specifiche, basta implementsfarlo (e, ovviamente, utilizzare queste costanti comuni nell'implementazione).

Esempio:

interface Drawable {

    double GOLDEN_RATIO = 1.618033988;
    double PI = 3.141592653;
    ...

    // methods
    ...
}

public class Circle implements Drawable {
    ...
    public double getCircumference() {
        return 2 * PI * r;
    }
}

void usage() {

    Circle circle = new Circle(radius: 3.0);
    double maxRadius = 5.0;

    if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
        ...
    }

}

In questo esempio:

  • Da Circle implements Drawable, si capisce subito che Circleprobabilmente è conforme alle costanti definite in Drawable, altrimenti devono scegliere un nome peggiore rispetto a quelli buoni PIed GOLDEN_RATIOè già stato preso!
  • Solo questi Drawableoggetti sono conformi allo specifico PIe GOLDEN_RATIOdefinito in Drawable, possono esserci oggetti che non sono Drawablecon diversa precisione di pi greco e sezione aurea.

Ho frainteso la tua risposta o fraintendi lo scopo di Interface? Un'interfaccia NON deve essere un sottoinsieme. Un'interfaccia è un contratto, che a seconda di quale sottoscrive il contratto deve fornire l'interazione specificata da quel contratto. L'unico utilizzo valido dell'interfaccia è utilizzarlo per dichiarare / adempiere a un contratto.
Blessed Geek

@BlessedGeek Rispetti un contratto, quindi l'abilità descritta dal contratto è un sottoinsieme di ciò che puoi fare.
Pioggia il

1

L' javax.swing.SwingConstantsinterfaccia è un esempio che ha dei campi statici che vengono utilizzati tra le classi swing. Ciò ti consente di utilizzare facilmente qualcosa di simile

  • this.add(LINE_START, swingcomponent);
  • this.add(this.LINE_START, swingcomponent); o
  • this.add(SwingComponents.LINE_START, swingcomponent);

Tuttavia questa interfaccia non ha metodi ...


1

Mi sono imbattuto in questa domanda e ho pensato di aggiungere qualcosa che non era menzionato. In generale, sono d'accordo con la risposta di Pascal qui . Tuttavia, non credo che le costanti su un'interfaccia siano "sempre" un antipattern.

Ad esempio, se le costanti che stai definendo fanno parte di un contratto per quell'interfaccia, penso che l'interfaccia sia un ottimo posto per le costanti. In alcuni casi, non è appropriato convalidare privatamente i parametri senza esporre il contratto agli utenti della tua implementazione. Senza un contratto pubblico, gli utenti possono solo indovinare con cosa stai convalidando, a meno di decompilare la classe e leggere il tuo codice.

Quindi, se implementi un'interfaccia e l'interfaccia ha le costanti che usi per garantire i tuoi contratti (come gli intervalli interi per esempio), un utente della tua classe può essere sicuro di utilizzare correttamente l'istanza dell'interfaccia controllando le costanti nell'interfaccia loro stessi. Ciò sarebbe impossibile se le costanti fossero private della tua implementazione o se la tua implementazione fosse privata del pacchetto o qualcosa del genere.


1
Il problema con le interfacce e le costanti nel modo in cui lo descrivi, puoi aggiungere una costante a un'interfaccia, ma non esiste alcun collegamento che imponga al consumatore della tua API di utilizzare effettivamente quella costante.
Daniel

@Daniel: ho votato positivamente il tuo commento ma ora ho una buona spiegazione per la tua domanda: "non esiste alcun vincolo che imponga al consumatore della tua API di utilizzare effettivamente quella costante" ma ora il client non può più utilizzare CONSTANT_NAME perché è stato usato, che è un buon segno per me!
Piove il

Quindi il nome della costante non è disponibile nella tua classe, ma ciò presuppone che nominerò la costante esattamente la stessa cosa. Usare un'interfaccia per rappresentare le costanti è ancora un errore, un'interfaccia è un contratto per un'API. Non dovrebbe in alcun modo essere utilizzato per rappresentare valori costanti.
Daniel

-1

Uso le costanti dell'interfaccia quando si tratta di costanti condivise tra le classi.

public interface TestConstants
{
    String RootLevelConstant1 = "RootLevelConstant1";

    interface SubGroup1
    {
        String SubGroupConstant1 = "SubGroup1Constant1";
        String SubGroupConstant2 = "SubGroup1Constant2";
    }

    interface SubGroup2
    {
        String SubGroupConstant1 = "SubGroup2Constant1";
        String SubGroupConstant2 = "SubGroup2Constant2";
    }
}

Il raggruppamento è una risorsa enorme, soprattutto con un ampio insieme di costanti.

Per usarli, li incateni semplicemente insieme:

System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);

Sono d'accordo. Fa fondamentalmente la stessa cosa della classe astratta pubblica con campi finali statici pubblici ma in molte meno parole. Tutto ciò di cui hai bisogno è assicurarti che tutti gli sviluppatori del tuo team seguano le buone pratiche e non implementino queste interfacce.
Yahor

1
Questo è orribile perché puoi fare esattamente lo stesso con Classes, accedere allo stesso modo, oltre a rendere le classi finali e i loro costruttori privati ​​(se vuoi davvero solo un sacco di costanti insieme). Inoltre eviti che le persone prolunghino la tua classe. Non puoi evitare che le persone implementino la tua interfaccia, vero?
GabrielOshiro

1
Perché in una classe quello che puoi fare in un'interfaccia ?? Il problema è come impedire alle persone di implementare inavvertitamente QUALSIASI interfaccia. Perché scegli le costanti dell'interfaccia?
Blessed Geek

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.