La "interfaccia statica" è una buona pratica?

13

Ho appena notato che esiste un'opzione per avere metodi statici nelle interfacce. Come con i campi di interfaccia statici, esiste un comportamento interessante: questi non sono ereditati.

Non sono sicuro che sia utile nelle effettive interfacce che devono essere implementate. Tuttavia, consente al programmatore di creare interfacce che sono solo buste per materiale statico, come ad es. le classi di utilità sono.

Un semplice esempio è solo una busta per le costanti globali. Rispetto ad una classe, puoi facilmente notare la piastra mancante di public static final come si suppone (rendendola meno dettagliata).

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

Potresti anche creare qualcosa di più complesso, come questo pseudo-enum di chiavi di configurazione.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

In questo modo potresti anche creare qualche "classe" di utilità. Tuttavia, nelle utility, è spesso utile utilizzare metodi di helper privati o protetti, il che non è del tutto possibile nelle classi.

Lo considero una bella nuova funzionalità, e soprattutto il fatto che i membri statici non siano ereditati è un concetto interessante che è stato introdotto solo per le interfacce.

Mi chiedo se puoi considerarlo una buona pratica. Mentre lo stile del codice e le migliori pratiche non sono assiomatiche e c'è spazio per un'opinione, penso che di solito ci siano validi motivi per sostenere l'opinione.

Sono più interessato ai motivi (non) di utilizzare modelli come questi.

Si noti che non intendo implementare tali interfacce. Sono semplicemente una busta per il loro contenuto statico. Intendo solo utilizzare le costanti o i metodi e possibilmente usare l'importazione statica.

    
posta Vlasec 16.12.2016 - 03:00
fonte

5 risposte

1

A simple example is just an envelope for global constants.

Mettere costanti sulle interfacce è chiamato Constant Interface Antipattern poiché le costanti sono spesso solo un dettaglio di implementazione. Ulteriori inconvenienti sono riepilogati nell'articolo di Wikipedia sull'interfaccia Constant .

You could also create some utility "class" this way.

In effetti il documento Java afferma che i metodi statici possono facilitare organizzare i metodi di supporto, ad esempio quando si chiamano i metodi di supporto dai metodi predefiniti.

    
risposta data 16.12.2016 - 11:11
fonte
1

Come indicato nella domanda, l'interfaccia non è pensata per essere implementata (o istanziata). Quindi potremmo confrontarlo con una classe che ha un costruttore privato:

  • La classe non può essere estesa senza super() da chiamare, ma l'interfaccia può essere "implementata"
  • La classe non può essere istanziata senza riflessi, mentre l'interfaccia può essere facilmente istanziata come una classe anonima semplice come questa: new MyInterface() {};

Questo confronto è a favore della classe in quanto consente un maggiore controllo. Detto questo, la classe non è destinata ad essere un detentore di materiale statico, ti aspetteresti che abbia istanze. Bene, non c'è un'opzione perfetta.

C'è anche una cosa strana riguardo l'ereditarietà dall'interfaccia statica:

  • Una classe "implementazione" eredita i campi, ma non eredita i metodi statici
  • Un'interfaccia estesa non eredita affatto membri statici
  • (Mentre una classe che estende una classe eredita ogni membro non privato ... e poiché non può essere estesa da un'interfaccia, c'è meno spazio per la confusione)

Questi potrebbero essere motivi per ritenerlo un modello errato e continuare a utilizzare classi statiche per questi casi. Tuttavia, per qualcuno dipendente da zucchero sintattico potrebbe essere ancora tentato anche con i lati negativi.

    
risposta data 16.12.2016 - 16:29
fonte
0

Come @MarkusPscheidt questa idea è essenzialmente un'estensione del Interfaccia costante antipattern. Questo approccio è stato inizialmente ampiamente utilizzato per consentire a un singolo insieme di costanti di essere ereditato da molte classi disparate. La ragione per cui questo finiva di essere considerato un antipattern era a causa dei problemi che si incontravano usando questo approccio nei progetti reali. Non vedo alcun motivo per pensare che questi problemi si riferiscano solo alle costanti.

Probabilmente ancora più importante, non c'è davvero bisogno di farlo. Utilizza invece importazioni statiche e sii esplicito su cosa stai importando e da dove.

    
risposta data 16.12.2016 - 19:56
fonte
0

Direi, se sei interessato a come utilizzare correttamente la nuova funzione, dai un'occhiata al codice nel JDK. I metodi predefiniti sulle interfacce sono molto usati e facili da trovare, ma i metodi statici sulle interfacce sembrano essere molto rari. Alcuni esempi includono java.time.chrono.Chronology , java.util.Comparator , java.util.Map e alcune interfacce in java.util.function e java.util.stream .

La maggior parte degli esempi che ho esaminato riguardano gli usi di quelle API che sono probabilmente molto comuni: la conversione tra diversi tipi nell'API del tempo, ad esempio, per confronti che sono probabilmente eseguiti frequentemente tra oggetti passati a funzioni o oggetti contenuti in collezioni. Il mio take-away: se c'è una parte della tua API che deve essere flessibile, ma puoi coprire l'80% dei casi d'uso con una manciata di valori predefiniti, considera l'utilizzo di metodi statici sulle tue interfacce. Considerata la scarsa frequenza con cui questa caratteristica sembra essere utilizzata nel JDK, sarei molto prudente quando la uso nel mio codice.

I tuoi esempi non assomigliano a quello che vedo nel JDK. Per quei casi specifici, dovresti quasi certamente creare un enum che implementa l'interfaccia desiderata. Un'interfaccia descrive un insieme di comportamenti e in realtà non ha attività che mantengano una raccolta delle sue implementazioni.

    
risposta data 16.12.2016 - 19:59
fonte
-1

I wonder if there are reasons not to use it.

Che ne dici, um, della compatibilità con le JVM più vecchie?

Do you consider this a good idea in general?

No. È un cambiamento incompatibile all'indietro che aggiunge zilch all'espressività del linguaggio. Due pollici in giù.

Are there some model situations where you strongly recommend classes?

Raccomando vivamente di utilizzare le classi per contenere i dettagli di implementazione. Un'interfaccia è in realtà solo per dire "questo oggetto supporta le operazioni XYZ" e questo non ha nulla a che fare con i metodi statici che potresti pensare di inserire nella dichiarazione dell'interfaccia. Questa funzione è come una poltrona reclinabile con un mini-frigo incorporato. Certo ha alcuni usi di nicchia ma non tira abbastanza peso da meritare di essere mainstream.

UPDATE: per favore non più downvotes. Chiaramente alcune persone pensano che i metodi statici nelle interfacce siano le ginocchia delle api, e io con questo mi sto capitolando. Avrei appena eliminato questa risposta ma i commenti ad esso allegati sono una discussione interessante.

    
risposta data 16.12.2016 - 03:24
fonte

Leggi altre domande sui tag