À quoi servent les constantes d'interface?

123

J'apprends Java et je viens de découvrir que l'interface peut avoir des champs, qui sont publics statiques et définitifs. Je n'ai vu aucun exemple de ceux-ci jusqu'à présent. Quels sont certains des cas d'utilisation de ces constantes d'interface et puis-je en voir dans la bibliothèque standard Java?

unj2
la source

Réponses:

190

Mettre des membres statiques dans une interface (et implémenter cette interface) est une mauvaise pratique et il y a même un nom pour cela, l' antipattern d'interface constante , voir Effective Java , Item 17:

Le modèle d'interface constant est une mauvaise utilisation des interfaces . Le fait qu'une classe utilise certaines constantes en interne est un détail d'implémentation. L'implémentation d'une interface constante entraîne la fuite de ce détail d'implémentation dans l'API exportée de la classe. Cela n'a aucune conséquence pour les utilisateurs d'une classe que la classe implémente une interface constante. En fait, cela peut même les confondre. Pire encore, cela représente un engagement: si dans une prochaine version la classe est modifiée pour ne plus avoir besoin d'utiliser les constantes, elle doit quand même implémenter l'interface pour assurer la compatibilité binaire. Si une classe non finale implémente une interface constante, toutes ses sous-classes verront leurs espaces de noms pollués par les constantes de l'interface.

Il existe plusieurs interfaces constantes dans les bibliothèques de la plateforme Java, telles que java.io.ObjectStreamConstants. Ces interfaces doivent être considérées comme des anomalies et ne doivent pas être émulées.

Pour éviter certains pièges de l'interface constante (car vous ne pouvez pas empêcher les gens de l'implémenter), une classe appropriée avec un constructeur privé doit être préférée (exemple emprunté à 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;
}

Et pour accéder aux constantes sans avoir à les qualifier complètement (c'est-à-dire sans avoir à les préfixer avec le nom de la classe), utilisez un import statique (depuis Java 5):

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

public class Calculations {

    public double getReducedPlanckConstant() {
        return PLANCK_CONSTANT / (2 * PI);
    }
}
Pascal Thivent
la source
12
Ok, mais que faire si vous avez une interface qui n'est pas seulement pour une définition constante. J'ai donc une interface qui est implémentée par de nombreuses classes, elle contient des déclarations de méthodes mais je veux aussi y ajouter des valeurs communes comme la taille par exemple. Est-ce vraiment un mauvais modèle dans ce cas. En général, je suis d'accord que la création d'interfaces uniquement pour les constantes est un anti-modèle.
Łukasz Rzeszotarski
11
Ce n'est pas une mauvaise chose uniquement parce que quelqu'un le dit dans un livre. Tant que vous n'implémentez pas cette interface pour accéder à ces constantes, c'est OK.
ACV
11
Non Non Non. Cette citation dans Effective Java concerne autre chose! La création d'interfaces de constantes uniquement est une meilleure alternative aux classes contenant ces constantes. Un java efficace dit: "Qu'une classe utilise certaines constantes en interne est un détail d'implémentation". Mais ici ce n'est pas le cas. Nous parlons de constantes «globales». Et qui voudrait implémenter une interface sans déclaration de méthode?
ACV
6
Je suis d'accord avec ACV. Si l'interface constante ne fait pas partie du module API exporté ou lorsqu'elle n'est implémentée nulle part, je ne vois pas le problème. Utiliser les classes finales const est moche: vous avez besoin d'un constructeur privé qui encombre le code car il n'a aucune utilité.
Lawrence le
2
Cette réponse ne présente pas correctement le point principal du livre "Effective Java", car il "rétrograde" le point principal en le mettant entre crochets: "(et implémentant cette interface)". Au lieu de cela, il met l'accent sur le point des constantes dans les interfaces (ce qui est OK sauf si vous implémentez une telle interface). Ce n'est généralement pas une mauvaise réponse, car si vous lisez attentivement le fragment cité, vous pouvez voir ce que signifiait à l'origine l'auteur de "Effective Java". Mais je trouve cela trompeur. À mon avis, la partie «et la mise en œuvre de cette interface» devrait être en gras pour la souligner.
krm
17

" Le modèle d'interface constant est une mauvaise utilisation des interfaces "

Quiconque a concocté cette hypothèse, quelque gourou qu'il soit, l'a concoctée sur la base de la nécessité de continuer à mettre en œuvre efficacement les mauvaises habitudes et pratiques. L'hypothèse est basée sur la promotion de la validité des mauvaises habitudes de conception de logiciels.

J'ai écrit une réfutation de réponse contre cette hypothèse ici: Quelle est la meilleure façon d'implémenter des constantes en Java? expliquant le caractère sans fondement de cette hypothèse.

Pendant 10 ans, cette question était restée ouverte, jusqu'à ce qu'elle soit close dans les 2 heures après que j'aie affiché mes raisons justifiant cette hypothèse, exposant ainsi la NON-Volonté de débattre de ceux qui s'accrochent à cette hypothèse erronée.

Ce sont les points que j'ai exprimés contre l'hypothèse

  • La base de cette hypothèse est le besoin de méthodes et de règles RESTRICTIVES pour faire face aux effets des mauvaises habitudes et méthodologies logicielles.

  • Les partisans du sentiment " Le modèle d'interface constant est une mauvaise utilisation des interfaces" sont incapables de fournir d'autres raisons que celles causées par la nécessité de faire face aux effets de ces mauvaises habitudes et pratiques.

  • Résolvez le problème fondamental.

  • Et puis pourquoi ne pas utiliser pleinement et exploiter toutes les fonctionnalités du langage de la structure du langage Java à votre convenance. Aucune veste requise. Pourquoi inventer des règles pour barricader votre mode de vie inefficace pour discriminer et incriminer des modes de vie plus efficaces?

La question fondamentale

est l'organisation de l'information. Les informations servant de médiateur au processus, et le comportement de ces informations doivent d'abord être compris, ainsi que les soi-disant règles métier - avant de concevoir ou de compléter des solutions au processus. Cette méthode d'organisation de l'information s'appelait il y a quelques décennies la normalisation des données.

Alors seule l'ingénierie d'une solution sera possible car aligner la granularité et la modularité des composants d'une solution avec la granularité et la modularité des composants de l'information est la stratégie optimale.

Il existe deux ou trois obstacles importants à l'organisation de l'information.

  1. Le manque de perception de la nécessité d'une «normalisation» des modèles de données.

  2. Les déclarations d'EF Codd sur la normalisation des données sont erronées, défectueuses et ambiguës.

  3. La dernière mode qui se fait passer pour une ingénierie agile est la notion erronée selon laquelle il ne faut pas planifier et conditionner l'organisation des modules à l'avance, car vous pouvez la refactoriser au fur et à mesure. La refactorisation et le changement continu sans être entravés par de futures découvertes sont utilisés comme excuse. Les découvertes essentielles du comportement des informations de processus sont alors, en utilisant des astuces comptables pour retarder les profits et l'actifisation, c'est pourquoi les connaissances essentielles et leur traitement ne sont pas jugées nécessaires maintenant.

L'utilisation des constantes d'interface est une bonne pratique.

N'inventez pas de règles et n'émettez aucune fatwa contre cela simplement parce que vous aimez vos habitudes de programmation ponctuelles.

N'interdisez pas la possession d'armes à feu au motif qu'il y a des gens qui ne savent pas comment manier les armes ou qui sont enclins à abuser des armes à feu.

Si les règles que vous concoctez sont destinées à des novices en programmation incapables de coder professionnellement et que vous vous comptez parmi eux, dites-le - ne déclarez pas votre fatwa comme applicable à des modèles de données correctement normalisés.

Un raisonnement idiot - Les interfaces n'étaient pas destinées par les patrouilleurs du langage Java à être utilisées de cette façon?

Je me fiche de ce que les intentions originales des pères fondateurs avaient pour la Constitution américaine. Je me fiche des intentions non écrites et non codifiées. Je ne me soucie que de ce qui est littéralement codifié dans la Constitution écrite et de la manière dont je peux les exploiter pour le fonctionnement efficace de la société.

Je ne me soucie que de ce que me permettent les spécifications du langage / plate-forme Java et j'ai l'intention de les exploiter au maximum pour me donner un moyen d'exprimer mes solutions logicielles de manière efficace et efficiente. Aucune veste requise.

L'utilisation des constantes Enum est en fait une pratique horrible.

Il faut écrire du code supplémentaire pour mapper le paramètre à la valeur. Le fait que les fondateurs de Java n'aient pas fourni de mappage paramètre-valeur sans que vous ayez écrit ce code de mappage démontre que les constantes Enum sont tout aussi une utilisation non intentionnelle du langage Java.

D'autant que vous n'êtes pas encouragé à normaliser et à composant vos paramètres, il y aurait une fausse impression que les paramètres mélangés dans un sac Enum appartiennent à la même dimension.

Les constantes sont un contrat API

N'oublie pas ça. Si vous avez conçu et normalisé votre modèle de données et qu'il inclut des constantes, ces constantes sont des contrats. Si vous n'avez pas normalisé votre modèle de données, vous devez vous conformer aux fatwas données sur la façon de pratiquer le codage restrictif pour faire face à cette mauvaise habitude.

Par conséquent, les interfaces sont un moyen idéal de mettre en œuvre le contrat de Constants.

Une étrange présomption - Et si l'interface était implémentée par inadvertance.

Ouaip. N'importe qui pourrait implémenter par inadvertance une interface par inadvertance. Rien ne fera obstacle à de tels programmeurs par inadvertance.

Concevez et normalisez votre modèle de données contre les fuites

Ne placez pas de décrets restrictifs pour protéger les mauvaises pratiques présumées qui provoquent la fuite de paramètres non contractuels / errants dans l'API. Résolvez le problème fondamental, plutôt que de rejeter la faute sur les constantes d'interface.

Ne pas utiliser d'EDI est une mauvaise pratique

Un programmeur fonctionnant normalement et EFFICACE n'est pas là pour prouver combien de temps elle peut rester sous l'eau, jusqu'où elle pourrait marcher dans une chaleur fulgurante ou des orages humides. Elle doit utiliser un outil efficace comme une voiture ou un bus ou au moins un vélo pour prendre ses 10 miles au travail tous les jours.

Ne placez pas de restrictions sur les autres programmeurs simplement parce que vous avez une obsession d'ascèse ésotérique avec la programmation sans IDE.

Quelques frameworks sont conçus pour aider les programmeurs à continuer à pratiquer efficacement les mauvaises habitudes.

OSGI est un tel cadre. Tout comme le décret contre les constantes d'interface.

Par conséquent, la réponse définitive ...

Les constantes d'interface sont un moyen efficace et efficient de placer dans un contrat des composants bien conçus et normalisés d'un modèle de données.

Les constantes d'interface dans une interface privée correctement nommée imbriquée dans un fichier de classe sont également une bonne pratique pour regrouper toutes vos constantes privées plutôt que de les disperser dans le fichier.

Geek béni
la source
29
Tous vos arguments pourraient être avancés sans blague, sarcasme, émotion. Stackoverflow n'est pas une plateforme de blogs.
tkruse
1
"Je me fiche de ce que les intentions originales des pères fondateurs avaient pour la Constitution américaine. Je me fiche des intentions non écrites non codifiées. Je me soucie seulement de ce qui est littéralement codifié dans la Constitution écrite et comment je peux les exploiter pour le fonctionnement efficace de la société. " - ce n'est pas une bonne allégorie?
Blessed Geek
"Cela nécessite l'écriture de code supplémentaire pour mapper le paramètre à la valeur. Le fait que les fondateurs de Java n'aient pas fourni de mappage paramètre-valeur sans votre écriture de ce code de mappage démontre que les constantes Enum sont tout aussi une utilisation non intentionnelle du langage Java." Sinon, comment obtiendriez-vous un mappage de valeur de paramètre sans écrire de code supplémentaire?
GabrielOshiro
Utilisez des constantes d'interface. EXACTEMENT.
Blessed Geek
9

Je suis tombé sur cette vieille question plusieurs fois maintenant et la réponse acceptée me confond toujours. Après beaucoup de réflexion, je pense que cette question peut être clarifiée davantage.

Pourquoi utiliser Interface Constant?

Comparez-les simplement:

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

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

contre

public interface Constants {

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

Même usage. Beaucoup moins de code.

Mauvaise pratique?

Je pense que la réponse de @Pascal Thivent est mal soulignée, en voici ma version:

Mettre des membres statiques dans une interface ( et implémenter cette interface ) est une mauvaise pratique.

La citation de Effective Java suppose que l'interface constante est mise en œuvre par d'autres, ce qui, à mon avis, ne devrait pas (et ne se produira pas).

Lorsque vous créez une interface constante nommée quelque chose comme Constants, elle ne doit être implémentée par personne. (bien que techniquement possible, ce qui est le seul problème ici)

Cela n'arrivera pas dans la bibliothèque standard

La bibliothèque standard ne peut pas se permettre une éventuelle mauvaise utilisation de la conception, vous n'en verrez donc pas.

Cependant , pour les projets quotidiens des développeurs normaux, en utilisant l' interface de constantes est beaucoup plus facile parce que vous n'avez pas besoin de vous soucier static, final, empty constructor, etc., et il ne causera aucun problème de mauvaise conception. Le seul inconvénient auquel je peux penser est qu'il porte toujours le nom d '"interface", mais rien de plus.

Débat sans fin

À la fin, je pense que tout le monde ne fait que citer des livres et donner des opinions et des justifications à leurs positions. Aucune exception pour moi. Peut-être que la décision appartient encore aux développeurs de chaque projet. N'hésitez pas à l'utiliser si vous vous sentez à l'aise. Le mieux que nous puissions faire est de le rendre cohérent tout au long du projet .

Nakamura
la source
"Mettre des membres statiques dans une interface (et implémenter cette interface) est une mauvaise pratique." Non, ce n'est pas
pleut
Le modificateur publicpeut également être omis puisqu'il s'agit d'une interface, ce qui en fait simplement double PI = 3.14159;Utilisation de Constants.PIn'a pas besoin de la classe qui l'utilise pour implémenter l' Constantsinterface! Je pense que l'approche de l'interface est beaucoup plus propre en termes d'utilisation, à
mon humble avis
@krozaine Mis à jour. Merci pour le rappel. Référence pour quiconque a des doutes: "Toutes les valeurs constantes définies dans une interface sont implicitement publiques, statiques et définitives." - docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html
Nakamura
6

Joshua Bloch, "Effective Java - Guide du langage de programmation":

Le modèle d'interface constant est une mauvaise utilisation des interfaces. Le fait qu'une classe utilise certaines constantes en interne est un détail d'implémentation. L'implémentation d'une interface constante entraîne la fuite de ce détail d'implémentation dans l'API exportée de la classe. Cela n'a aucune conséquence pour les utilisateurs d'une classe que la classe implémente une interface constante. En fait, cela peut même les confondre. Pire encore, cela représente un engagement: si dans une prochaine version la classe est modifiée pour ne plus avoir besoin d'utiliser les constantes, elle doit toujours implémenter l'interface pour assurer la compatibilité binaire. Si une classe non finale implémente une interface constante, toutes ses sous-classes verront leurs espaces de noms pollués par les constantes de l'interface.

empileur
la source
Vous n'avez littéralement rien ajouté de valeur qui n'ait déjà été dit.
Donal Fellows
2

Il y a des réponses qui sont très raisonnables.

Mais j'ai quelques réflexions sur cette question. (peut être faux)

À mon avis, les champs dans une interface, ne doivent pas être des constantes pour l'ensemble du projet, ce ne sont que des moyens pour l'interface et les interfaces l'étendent et les classes qui implémentent ces interfaces ou ont une relation étroite avec elles. Ils doivent être utilisés dans une certaine plage non globale.

Zhili
la source
Ils doivent en effet être utilisés dans ces classes d'implémentation.
pleut le
2

Deux points sur l'interface:

  • Une interface décrit un sous-ensemble de ce qu'un objet qui l'implémente peut faire. (C'est l'intuition)

  • Une interface décrit des constantes communes suivies d' objets qui l'implémentent.

    • Ces constantes communes sont destinées à être connues du client pour en savoir plus sur ces objets.
    • Donc, Constantes Interface est en effet contre-intuitif pour définir des constantes globales , puisque l'interface est utilisée pour décrire certains objets , pas tous les objets / aucun objet (considérez la signification de global ).

Donc, je pense que si l' interface des constantes n'est pas utilisée pour les constantes globales , alors c'est acceptable:

  • Si ces constantes communes ont de bons noms, ils recommanderont à l'implémenteur de les utiliser (voir mon premier point pour l'exemple ci-dessous)
  • Si une classe veut se synchroniser avec ces classes suivant la spécification, juste implementselle (et, bien sûr, utilisez ces constantes communes dans l'implémentation).

Exemple:

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 ) {
        ...
    }

}

Dans cet exemple:

  • De Circle implements Drawable, vous savez immédiatement qu'il Circleest probablement conforme aux constantes définies dans Drawable, sinon ils doivent choisir un pire nom depuis les bons PIet GOLDEN_RATIOa déjà été pris!
  • Seuls ces Drawableobjets sont conformes au spécifique PIet GOLDEN_RATIOdéfinis dans Drawable, il peut y avoir des objets qui ne sont pas Drawableavec une précision différente de pi et de nombre d'or.
Il pleut
la source
Ai-je mal compris votre réponse ou mal compris le but d'Interface? Une interface ne doit PAS être un sous-ensemble. Une interface est un contrat, que celui qui souscrit au contrat doit fournir l'interaction spécifiée par ce contrat. La seule utilisation valide de l'interface est de l'utiliser pour déclarer / exécuter un contrat.
Blessed Geek
@BlessedGeek Vous remplissez un contrat, alors la capacité décrite par le contrat est un sous-ensemble de ce que vous pouvez faire.
pleut le
1

L' javax.swing.SwingConstantsinterface est un exemple qui a des champs statiques qui sont utilisés parmi les classes swing. Cela vous permet d'utiliser facilement quelque chose comme

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

Cependant cette interface n'a pas de méthodes ...

Progman
la source
1

Je suis tombé sur cette question et j'ai pensé ajouter quelque chose qui n'était pas mentionné. En général, je suis d'accord avec la réponse de Pascal ici . Cependant, je ne pense pas que les constantes sur une interface soient «toujours» un anti-modèle.

Par exemple, si les constantes que vous définissez font partie d'un contrat pour cette interface, je pense que l'interface est un endroit idéal pour les constantes. Dans certains cas, il n'est tout simplement pas approprié de valider vos paramètres en privé sans exposer le contrat aux utilisateurs de votre implémentation. Sans contrat public, les utilisateurs ne peuvent que deviner avec quoi vous validez, à moins de décompiler la classe et de lire votre code.

Donc, si vous implémentez une interface et que l'interface a les constantes que vous utilisez pour garantir vos contrats (comme des plages d'entiers par exemple), alors un utilisateur de votre classe peut être sûr qu'il utilise correctement l'instance d'interface en comparant les constantes dans l'interface se. Cela serait impossible si les constantes étaient privées pour votre implémentation ou si votre implémentation était un package privé ou quelque chose.

akagixxer
la source
1
Le problème avec les interfaces et les constantes comme vous le décrivez, vous pouvez ajouter une constante à une interface, mais il n'y a pas de liaison qui oblige le consommateur de votre API à utiliser réellement cette constante.
Daniel
@Daniel: J'ai voté pour votre commentaire, mais maintenant j'ai une bonne explication à votre question: "il n'y a pas de liaison qui oblige le consommateur de votre API à utiliser réellement cette constante" mais maintenant le client ne peut plus utiliser le CONSTANT_NAME parce qu'il a été d'occasion, ce qui est bon signe pour moi!
pleut du
Le nom de la constante n'est donc pas disponible dans votre classe, mais cela suppose que je vais nommer la constante exactement la même chose. Utiliser une interface pour représenter des constantes est toujours une erreur, une interface est un contrat pour une API. Il ne doit en aucun cas être utilisé pour représenter des valeurs constantes.
Daniel
-1

J'utilise des constantes d'interface lorsque je traite des constantes partagées entre les classes.

public interface TestConstants
{
    String RootLevelConstant1 = "RootLevelConstant1";

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

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

Le regroupement est un énorme atout, surtout avec un grand ensemble de constantes.

Pour les utiliser, il vous suffit de les enchaîner:

System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);
jared
la source
Je serais d'accord. Il fait fondamentalement la même chose que la classe abstraite publique avec des champs finaux statiques publics mais en beaucoup moins de mots. Tout ce dont vous avez besoin est de vous assurer que tous les développeurs de votre équipe suivent les bonnes pratiques et n'implémentent pas ces interfaces.
Yahor
1
C'est horrible car vous pouvez faire exactement la même chose avec les classes, accéder de la même manière, et rendre les classes finales et leurs constructeurs privés (si vous voulez vraiment juste un sac de constantes ensemble). De plus, vous évitez les gens d'étendre votre classe. Vous ne pouvez pas éviter que les gens implémentent votre interface, n'est-ce pas?
GabrielOshiro
1
Pourquoi faire dans une classe ce que vous pouvez faire dans une interface ?? Comment puis-je empêcher les gens d'implémenter par inadvertance N'IMPORTE QUELLE interface est la question. Pourquoi choisissez-vous les constantes d'interface?
Blessed Geek
-2

Les champs doivent être déclarés dans une interface afin qu'ils soient plus faciles à partager et puissent être référencés sans introduire de couplage supplémentaire.

Source: Style de codage des outils de développement Java

Esprit maître
la source
peut-être avant java6. mais ce n'est généralement pas pertinent aujourd'hui.
tkruse
Et le lien est rompu. Codepro n'est plus.
Stephen C