Quelle est la meilleure façon d'implémenter des constantes en Java? [fermé]


372

J'ai vu des exemples comme celui-ci:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

et supposé que je pourrais avoir une classe Constantes pour envelopper les constantes, les déclarant statiques finales. Je ne connais pratiquement pas Java du tout et je me demande si c'est la meilleure façon de créer des constantes.


1
juste pour ajouter des constantes java: public / privé
ms_27

Réponses:


403

C'est parfaitement acceptable, probablement même la norme.

(public/private) static final TYPE NAME = VALUE;

TYPEest le type, NAMEest le nom dans toutes les majuscules avec des soulignements pour les espaces, et VALUEest la valeur constante;

Je recommande fortement de NE PAS mettre vos constantes dans leurs propres classes ou interfaces.

En remarque: les variables déclarées finales et mutables peuvent toujours être modifiées; cependant, la variable ne peut jamais pointer vers un objet différent.

Par exemple:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

C'est légal et ce ORIGINserait alors un point à (3, 0).


19
Vous pouvez même «importer des MaxSeconds.MAX_SECONDS statiques;» pour que vous n'ayez pas à l'épeler MaxSeconds.MAX_SECONDS
Aaron Maenpaa

23
Le commentaire précédent sur l'importation statique s'applique uniquement à Java 5+. Certains pensent que la sténographie ne vaut pas la confusion possible quant à l'origine de la constante, lors de la lecture du code long, MaxSeconds.MAX_SECONDS peut être plus facile à suivre, puis à remonter et à regarder les importations.
MetroidFan2002

5
Parce que vous pouvez changer l'objet comme jjnguy l'a montré, il est préférable que vos constats soient des objets immuables ou simplement des primitives / chaînes simples.
marcospereira

14
Si vous lisez cette question, veuillez lire les deux réponses ci-dessous avant de prendre cette réponse trop au sérieux, même si elle est acceptée, elle est controversée sinon erronée.
orbfish

3
@jjnguy vous ne vous trompez pas, mais si je lis seulement la question et les deux premières lignes de votre réponse, j'aurais l'impression qu'une "classe de constantes" est "parfaitement acceptable, probablement même la norme". Cette notion est fausse.
Zach Lysobey

235

Je déconseille fortement d'avoir une seule classe de constantes. Cela peut sembler une bonne idée à l'époque, mais lorsque les développeurs refusent de documenter les constantes et que la classe se développe pour englober plus de 500 constantes qui ne sont pas du tout liées les unes aux autres (étant liées à des aspects entièrement différents de l'application), cela se transforme généralement en un fichier de constantes complètement illisible. Au lieu:

  • Si vous avez accès à Java 5+, utilisez des énumérations pour définir vos constantes spécifiques pour un domaine d'application. Toutes les parties de la zone d'application doivent faire référence à des énumérations, et non à des valeurs constantes, pour ces constantes. Vous pouvez déclarer une énumération similaire à la façon dont vous déclarez une classe. Les énumérations sont peut-être la caractéristique la plus (et sans doute la seule) utile de Java 5+.
  • Si vous avez des constantes qui ne sont valables que pour une classe particulière ou l'une de ses sous-classes, déclarez-les comme protégées ou publiques et placez-les sur la classe supérieure de la hiérarchie. De cette façon, les sous-classes peuvent accéder à ces valeurs constantes (et si d'autres classes y accèdent via public, les constantes ne sont pas seulement valables pour une classe particulière ... ce qui signifie que les classes externes utilisant cette constante peuvent être trop étroitement couplées à la classe contenant la constante)
  • Si vous avez une interface avec un comportement défini, mais que les valeurs renvoyées ou les valeurs d'argument doivent être particulières, il est parfaitement acceptable de définir des constantes sur cette interface afin que d'autres implémenteurs y aient accès. Cependant, évitez de créer une interface juste pour contenir des constantes: elle peut devenir aussi mauvaise qu'une classe créée juste pour contenir des constantes.

12
tout à fait d'accord ... cela peut être documenté comme un anti-modèle classique pour les grands projets.
Das

30
Hors sujet, mais ... Les génériques ne sont certainement pas parfaits, mais je pense que vous pourriez faire un assez bon cas pour qu'ils soient une fonctionnalité utile de Java 5 :)
Martin McNulty

3
@ ŁukaszL. La question elle-même est vraiment basée sur l'opinion (chaque fois que "le meilleur" survient, c'est généralement une question d'opinion), donc la réponse est une réponse valable à cette question. J'ai donné une réponse quant à ce que (oui, je crois , donc oui c'est une opinion, car encore une fois "le meilleur" change avec le temps et est généralement basé sur l'opinion) la meilleure façon d'implémenter des constantes en Java est.
MetroidFan2002

1
Aucune des options ci-dessus ne vous donne une vraie variable globale. Que se passe-t-il si j'ai quelque chose qui est utilisé partout mais qui n'est pas une énumération? Dois-je faire une énumération d'une seule chose?
markthegrea

1
Si vous avez besoin d'une constante globale qui couvre tous les modules, il y a probablement un problème avec votre stratégie de conception. Si vous avez vraiment besoin d'une constante globale, créez une classe finale publique pour celle-ci dans le package de niveau supérieur et collez-la là. Ensuite, supprimez-le dès que vous vous rendez compte pas tout vos classes n'ont pas réellement besoin de cette constante et déplacez-la vers le package qui la référence le plus. Vous pouvez partager une constante entre plusieurs packages, mais c'est une odeur de code d'exiger une constante globale qui n'est pas un type énuméré, car les types énumérés peuvent avoir un comportement, mais une chaîne est une chaîne, un int est un int, etc.
MetroidFan2002

120

C'est une MAUVAISE PRATIQUE d'utiliser des interfaces juste pour contenir des constantes (appelé motif d'interface constant par Josh Bloch). Voici ce que conseille Josh:

Si les constantes sont fortement liées à une classe ou une interface existante, vous devez les ajouter à la classe ou à l'interface. Par exemple, toutes les classes primitives numériques encadrées, telles que Integer et Double, exportent les constantes MIN_VALUE et MAX_VALUE. Si les constantes sont mieux considérés comme membres d'un type énuméré, vous devez les exporter avec un ENUM de type. Sinon, vous devez exporter les constantes avec une classe d'utilité non instanciable.

Exemple:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

À propos de la convention de dénomination:

Par convention, ces champs ont des noms composés de lettres majuscules, avec des mots séparés par des traits de soulignement. Il est essentiel que ces champs contiennent des valeurs primitives ou des références à des objets immuables.


23
Si vous appelez quelque chose de mauvaise pratique, vous devriez peut-être expliquer pourquoi vous pensez que c'est le cas.
GlennS

14
Il s'agit d'un ancien article, mais il vaut mieux utiliser la abstractnotation pour la classe plutôt que le constructeur privé.
Xtreme Biker

5
Matt, bien que la recommandation du motard ne soit pas fausse, je préconiserais des cours finaux plutôt que des cours abstraits. Le mot du motard en disant que c'était que vous voulez vous assurer que votre classe de constantes n'est pas modifiable. Donc, en le marquant comme final, vous ne lui permettez pas d'être sous-classé ou instancié. Cela aide également à encapsuler sa fonctionnalité statique et ne permet pas aux autres développeurs de la sous-classer et de lui faire faire des choses pour lesquelles elle n'a pas été conçue.
liltitus27

7
@XtremeBiker Marquer la classe abstractau lieu d'un constructeur privé n'empêche pas complètement l'instanciation, car on pourrait la sous-classer et instancier la sous-classe (non pas que ce soit une bonne idée de le faire, mais c'est possible). @ToolmakerSteve Vous ne pouvez pas sous-classer une classe avec un constructeur privé (du moins pas sans un gros mauvais hack), car le constructeur de la sous-classe doit appeler le constructeur (désormais privé) de sa superclasse. Donc, le marquer finalest inutile (mais peut-être plus explicite).
importez ce

3
Il est encore pire d'utiliser la classe juste pour contenir des constantes. Si vous ne voulez jamais créer un objet de cette classe, pourquoi utilisez-vous la classe régulière en premier lieu?
MaxZoom

36

Dans Effective Java (2e édition), il est recommandé d'utiliser des énumérations au lieu d'entiers statiques pour les constantes.

Il y a une bonne description des énumérations en Java ici: http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

Notez qu'à la fin de cet article, la question posée est:

Alors, quand devez-vous utiliser des énumérations?

Avec une réponse de:

Chaque fois que vous avez besoin d'un ensemble fixe de constantes


21

Évitez simplement d'utiliser une interface:

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

Il est tentant, mais viole l'encapsulation et brouille la distinction des définitions de classe.


1
En effet, les importations statiques sont de loin préférables.
Aaron Maenpaa

1
Cette pratique est une utilisation étrange des interfaces, qui sont destinées à énoncer les services fournis par une classe.
Rafa Romero

1
Je ne suis pas en désaccord avec le fait d'éviter d'utiliser l'interface pour les constantes, mais votre exemple est trompeur, je pense. Vous n'avez pas besoin d'implémenter l'interface pour accéder à la constante car elle est implicitement statique, publique et finale. Donc, c'est plus simple que ce que vous avez décrit ici.
djangofan

C'est vrai ... cela viole l'encapsulation, je préfère utiliser la classe Constant finale qui semble plus orientée objet et préférable à l'interface OR enum . Remarque: l' énumération peut être évitée si Android n'est pas nécessaire.
CoDe

19

J'utilise l'approche suivante:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

Que, par exemple, j'utilise Constants.DB.Connection.URLpour être constant. Il me semble plus "orienté objet" que pour moi.


4
Intéressant, mais encombrant. Pourquoi ne créeriez-vous pas à la place des constantes dans la classe qui leur est la plus étroitement associée, comme recommandé par d'autres? Par exemple, dans votre code DB ailleurs, avez-vous une classe de base pour vos connexions? Par exemple, "ConnectionBase". Ensuite, vous pouvez y mettre les constantes. Tout code qui fonctionne avec des connexions aura probablement déjà une importation qui peut simplement dire "ConnectionBase.URL" plutôt que "Constants.DB.Connection.URL".
ToolmakerSteve

3
@ToolmakerSteve Mais qu'en est-il des constantes générales que plusieurs classes peuvent utiliser? par exemple, les styles, les URL des services Web, etc ...?
Daniel Gomez Rico

Mettre toutes les constantes dans une classe a un avantage: la maintenance. Vous savez toujours exactement où trouver les constantes. Je ne dis pas que cela améliore cette technique, je ne donne qu'un avantage. Et ce que @ albus.ua a fait, c'est classer ses constantes, ce qui est une très bonne idée, surtout si la classe des constantes contient beaucoup de valeurs constantes. Cette technique aidera à maintenir la classe gérable et aidera à mieux décrire le but de la constante.
Nelda.techspiress

17

La création de constantes finales statiques dans une classe distincte peut vous poser des problèmes. Le compilateur Java optimisera réellement cela et placera la valeur réelle de la constante dans n'importe quelle classe qui la référence.

Si vous modifiez plus tard la classe 'Constants' et que vous ne recompilez pas dur sur d'autres classes qui référencent cette classe, vous vous retrouverez avec une combinaison d'anciennes et de nouvelles valeurs utilisées.

Au lieu de les considérer comme des constantes, considérez-les comme des paramètres de configuration et créez une classe pour les gérer. Faites en sorte que les valeurs ne soient pas définitives et envisagez même d'utiliser des getters. À l'avenir, comme vous déterminerez que certains de ces paramètres devraient être configurables par l'utilisateur ou l'administrateur, ce sera beaucoup plus facile à faire.


+1 pour cette excellente mise en garde. (Si vous ne pouvez pas garantir qu'il s'agit d'une constante permanente, envisagez plutôt un getter, comme le mentionne big_peanut_horse.) La même chose s'applique avec const en C #, soit dit en passant: msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
Jon Coombs

13

L'erreur numéro un que vous pouvez faire est de créer une classe accessible à l'échelle mondiale appelée avec un nom générique, comme les constantes. Cela est simplement jonché d'ordures et vous perdez toute capacité à déterminer quelle partie de votre système utilise ces constantes.

Au lieu de cela, les constantes doivent entrer dans la classe qui les "possède". Avez-vous une constante appelée TIMEOUT? Il devrait probablement aller dans votre classe Communications () ou Connection (). MAX_BAD_LOGINS_PER_HOUR? Va dans Utilisateur (). Et ainsi de suite.

L'autre utilisation possible est les fichiers Java .properties lorsque des "constantes" peuvent être définies au moment de l'exécution, mais pas facilement modifiables par l'utilisateur. Vous pouvez les empaqueter dans vos .jars et les référencer avec le Class resourceLoader.


Et bien sûr, vous ne voudriez jamais accéder à une constante de plus d'une classe, ou éviter l'encombrement au sommet d'une classe.
orbfish

6

C'est la bonne façon de procéder.

Généralement, les constantes ne sont pas conservées dans des classes "Constantes" distinctes car elles ne sont pas détectables. Si la constante est pertinente pour la classe actuelle, les garder là aide le développeur suivant.



5

Je préfère utiliser des getters plutôt que des constantes. Ces getters peuvent retourner des valeurs constantes, par exemplepublic int getMaxConnections() {return 10;} , mais tout ce qui a besoin de la constante passera par un getter.

Un avantage est que si votre programme dépasse la constante - vous trouvez qu'il doit être configurable - vous pouvez simplement changer la façon dont le getter renvoie la constante.

L'autre avantage est que pour modifier la constante, vous n'avez pas à recompiler tout ce qui l'utilise. Lorsque vous référencez un champ final statique, la valeur de cette constante est compilée dans tout bytecode qui la référence.


5
Bien recompiler les classes de référencement n'est guère un fardeau au 21e siècle. Et vous ne devez jamais utiliser le modèle accesseur / mutateur (getter / setter) pour autre chose que l'accès et la mutation des variables membres. Conceptuellement, les constantes sont censées être de nature immédiate, tandis que les getter / setters sont (les deux) destinés à gérer l' état . De plus, vous ne demandez que de la confusion: les gens ne s'attendront pas à ce qu'un getter produise une simple constante.

5

Je suis d'accord que l'utilisation d'une interface n'est pas la voie à suivre. Éviter ce modèle a même son propre élément (# 18) dans Bloch's Effective Java .

Un argument avancé par Bloch contre le modèle d'interface constante est que l'utilisation de constantes est un détail d'implémentation, mais l'implémentation d'une interface pour les utiliser expose ce détail d'implémentation dans votre API exportée.

Le public|private static final TYPE NAME = VALUE;modèle est un bon moyen de déclarer une constante. Personnellement, je pense qu'il vaut mieux éviter de faire une classe séparée pour héberger toutes vos constantes, mais je n'ai jamais vu de raison de ne pas le faire, à part les préférences et le style personnels.

Si vos constantes peuvent être bien modélisées comme une énumération, considérez la structure d' énumération disponible dans 1.5 ou version ultérieure.

Si vous utilisez une version antérieure à 1.5, vous pouvez toujours retirer les énumérations de typeafe en utilisant des classes Java normales. (Voir ce site pour en savoir plus).


Certaines constantes peuvent être utilisées pour appeler une API. Par exemple, voir interface org.springframework.transaction.TransactionDefinition. Il a une liste de constantes comme int PROPAGATION_REQUIRED = 0;
borjab

Je sais que c'est vieux, mais le lien vers Java efficace de Bloch est rompu. Pourriez-vous fournir une autre ou une autre référence soutenant que "l'utilisation d'une interface n'est pas la voie à suivre" s'il vous plaît?
Nelda.techspiress

4

Sur la base des commentaires ci-dessus, je pense que c'est une bonne approche pour changer la classe constante globale à l'ancienne (ayant des variables finales statiques publiques) en son équivalent enum d'une manière comme ceci:

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

Alors je peux les référer à aimer:

Constants.StringConstant.DB_HOST

4
Pourquoi? En quoi est-ce une amélioration? Chaque référence est désormais encombrante (Constants.StringConstant.wimporte). À mon humble avis, vous empruntez une route cahoteuse ici.
ToolmakerSteve

3

Une bonne conception orientée objet ne devrait pas nécessiter de nombreuses constantes accessibles au public. La plupart des constantes doivent être encapsulées dans la classe qui en a besoin pour faire son travail.


1
Ou injecté dans cette classe via le constructeur.
WW.

2

Il y a une certaine opinion pour y répondre. Pour commencer, les constantes en java sont généralement déclarées publiques, statiques et finales. Voici les raisons:

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

Je n'utiliserais jamais une interface pour un accesseur / objet CONSTANTS simplement parce que les interfaces devraient généralement être implémentées. Cela ne serait-il pas drôle:

String myConstant = IMyInterface.CONSTANTX;

Au lieu de cela, je choisirais entre plusieurs façons différentes, en fonction de certains petits compromis, et cela dépend donc de ce dont vous avez besoin:

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe

2

Quelle est la meilleure façon d'implémenter des constantes en Java?

Une approche que nous devons vraiment éviter : utiliser des interfaces pour définir des constantes.

Créer une interface spécifiquement pour déclarer des constantes est vraiment la pire des choses: cela vainc la raison pour laquelle les interfaces ont été conçues: définir le contrat de méthode (s).

Même si une interface existe déjà pour répondre à un besoin spécifique, y déclarer les constantes n'a vraiment aucun sens car les constantes ne devraient pas faire partie de l'API et du contrat fourni aux classes clientes.


Pour simplifier, nous avons globalement 4 approches valides .

Avec static final String/Integerchamp:

  • 1) en utilisant une classe qui déclare des constantes à l'intérieur mais pas seulement.
  • 1 variante) créant une classe dédiée à ne déclarer que des constantes.

Avec Java 5 enum:

  • 2) déclarer l'énumération dans une classe d'objet connexe (donc en tant que classe imbriquée).
  • 2 variante) créant l'énumération en tant que classe autonome (ainsi définie dans son propre fichier de classe).

TLDR: Quelle est la meilleure façon et où localiser les constantes?

Dans la plupart des cas, la méthode enum est probablement plus fine que la static final String/Integerméthode et personnellement, je pense que la static final String/Integerméthode ne doit être utilisée que si nous avons de bonnes raisons de ne pas utiliser les énumérations.
Et sur l'endroit où nous devons déclarer les valeurs constantes, l'idée est de rechercher s'il existe une seule classe existante qui possède une cohésion fonctionnelle spécifique et forte avec des valeurs constantes. Si nous trouvons une telle classe, nous devons l'utiliser comme support de constantes . Sinon, la constante ne doit être associée à aucune classe particulière.


static final String/ static final Integercontreenum

L'utilisation des énumérations est vraiment un moyen à prendre en considération.
Énumérations ont un grand avantage sur Stringou Integerchamp constant.
Ils définissent une contrainte de compilation plus forte. Si vous définissez une méthode qui prend l'énumération en paramètre, vous ne pouvez transmettre qu'une valeur d'énumération définie dans la classe enum (ou null).
Avec String et Integer, vous pouvez les remplacer par n'importe quelle valeur de type compatible et la compilation se passera bien même si la valeur n'est pas une constante définie dans les champs static final String/ static final Integer.

Par exemple, sous deux constantes définies dans une classe en tant que static final Stringchamps:

public class MyClass{

   public static final String ONE_CONSTANT = "value";
   public static final String ANOTHER_CONSTANT = "other value";
   . . .
}

Voici une méthode qui s'attend à avoir une de ces constantes comme paramètre:

public void process(String constantExpected){
    ...    
}

Vous pouvez l'invoquer de cette façon:

process(MyClass.ONE_CONSTANT);

ou

process(MyClass.ANOTHER_CONSTANT);

Mais aucune contrainte de compilation ne vous empêche de l'invoquer de cette façon:

process("a not defined constant value");

Vous auriez l'erreur uniquement lors de l'exécution et uniquement si vous effectuez à la fois une vérification de la valeur transmise.

Avec enum, les vérifications ne sont pas nécessaires car le client ne peut transmettre qu'une valeur enum dans un paramètre enum.

Par exemple, voici deux valeurs définies dans une classe enum (donc constante hors de la boîte):

public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

Voici une méthode qui s'attend à avoir l'une de ces valeurs d'énumération comme paramètre:

public void process(MyEnum myEnum){
    ...    
}

Vous pouvez l'invoquer de cette façon:

process(MyEnum.ONE_CONSTANT);

ou

process(MyEnum.ANOTHER_CONSTANT);

Mais la compilation ne vous permettra jamais de l'invoquer de cette façon:

process("a not defined constant value");

Où devons-nous déclarer les constantes?

Si votre application contient une seule classe existante qui possède une cohésion fonctionnelle spécifique et forte avec les valeurs constantes, le 1) et le 2) apparaissent plus intuitifs.
Généralement, cela facilite l'utilisation des constantes si celles-ci sont déclarées dans la classe principale qui les manipule ou qui a un nom très naturel pour deviner que nous les trouverons à l'intérieur.

Par exemple, dans la bibliothèque JDK, les valeurs exponentielles et constantes pi sont déclarées dans une classe qui déclare non seulement des déclarations constantes ( java.lang.Math).

   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

Les clients utilisant des fonctions mathématiques comptent souvent sur la Mathclasse. Ainsi, ils peuvent trouver des constantes assez facilement et peuvent également se rappeler où Eet PIsont définis de manière très naturelle.

Si votre application ne contient pas de classe existante qui a une cohésion fonctionnelle très spécifique et forte avec les valeurs constantes, les manières 1 variante) et 2 variante) apparaissent plus intuitives.
Généralement, cela ne facilite pas l'utilisation des constantes si celles-ci sont déclarées dans une classe qui les manipule alors que nous avons aussi 3 ou 4 autres classes qui les manipulent autant et qu'aucune de ces classes ne semble plus naturelle que les autres pour hôtes valeurs constantes.
Ici, définir une classe personnalisée pour ne contenir que des valeurs constantes est logique.
Par exemple, dans la bibliothèque JDK, l' java.util.concurrent.TimeUniténumération n'est pas déclarée dans une classe spécifique car il n'y a pas vraiment une et une seule classe spécifique JDK qui apparaît comme la plus intuitive pour la contenir:

public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}      

De nombreuses classes déclarées dans les java.util.concurrentutiliser: BlockingQueue, ArrayBlockingQueue<E>, CompletableFuture, ExecutorService, ... et vraiment pas l' un d'eux semble plus approprié de tenir le ENUM.


1

Une constante, de tout type, peut être déclarée en créant une propriété immuable dans une classe (c'est-à-dire une variable membre avec le finalmodificateur). En règle générale, les modificateurs staticet publicsont également fournis.

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

Il existe de nombreuses applications où la valeur d'une constante indique une sélection à partir d'un n-tuple (par exemple, une énumération ) de choix. Dans notre exemple, nous pouvons choisir de définir un type énuméré qui restreindra les valeurs attribuées possibles (c'est -à- dire une sécurité de type améliorée ):

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}

1

Une seule classe de constantes génériques est une mauvaise idée. Les constantes doivent être regroupées avec la classe à laquelle elles sont le plus logiquement liées.

Plutôt que d'utiliser des variables de toute nature (en particulier des énumérations), je vous suggère d'utiliser des méthodes. Créez une méthode portant le même nom que la variable et demandez-lui de renvoyer la valeur que vous avez affectée à la variable. Supprimez maintenant la variable et remplacez toutes les références à celle-ci par des appels à la méthode que vous venez de créer. Si vous pensez que la constante est suffisamment générique pour que vous ne deviez pas avoir à créer une instance de la classe juste pour l'utiliser, faites de la méthode constante une méthode de classe.


1

FWIW, une valeur de délai d'expiration en secondes devrait probablement être un paramètre de configuration (lu dans un fichier de propriétés ou par injection comme dans Spring) et non une constante.


1

Quelle est la différence

1.

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2.

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

et en utilisant MyGlobalConstants.TIMEOUT_IN_SECSpartout où nous avons besoin de cette constante. Je pense que les deux sont identiques.


1
Cela semble être essentiellement un commentaire en réponse à la réponse donnée par Bincob. Je pense qu'ils se comportent de manière très similaire, mais le point de bincob était qu'ils ne définissaient en aucune façon une interface. Et la suggestion était d'ajouter des constantes aux classes réelles, pas de créer une classe squelette MyGlobalConstants. (Bien que cela ait parfois un sens; utilisez une "classe statique" en ayant des constantes statiques et un constructeur privé pour empêcher l'instanciation; voir java.lang.math.) Envisagez d'utiliser enum.
Jon Coombs

Mettre également "final" dans la déclaration de classe empêchera le sous-classement. (En C #, vous pouvez faire "statique", ce qui signifie "résumé final", donc pas besoin de constructeur privé explicite.)
Jon Coombs

Oui, @JonCoombs mais "final" n'empêche pas son instanciation directe. Et Java interdit à la fois final et abstrait d'apparaître ensemble pour les classes, d'où le constructeur privé apparaissant sans fin pour empêcher à la fois l'instanciation ET le sous-classement. Je n'ai aucune idée de la raison pour laquelle le "résumé final" est interdit, sinon qu'il semble à première vue contradictoire dans sa façon de lire: "vous ne pouvez pas sous-classer mais cette classe est censée être sous-classée".

0

Je n'appellerais pas la classe la même (à part le casse) que la constante ... J'aurais au moins une classe de "Paramètres", ou "Valeurs", ou "Constantes", où toutes les constantes vivraient. Si j'en ai un grand nombre, je les regrouperais en classes logiques constantes (UserSettings, AppSettings, etc.)


Avoir une classe appelée Constants était ce que j'avais prévu de faire, ce n'était qu'un petit exemple que j'ai trouvé.
mk.

0

Pour aller plus loin, vous pouvez placer des constantes utilisées globalement dans une interface afin qu'elles puissent être utilisées à l'échelle du système. Par exemple

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

Mais ne l'implémentez pas. Il suffit de s'y référer directement dans le code via le nom de classe complet.


Le fait de les déclarer dans une interface (et de ne pas l'implémenter) est que vous pouvez manquer la "finale statique publique".
Tom Hawtin - tackline

9
Les interfaces sont destinées à définir un contrat comportemental, et non un mécanisme de commodité pour maintenir des constantes.
John Topley

@JohnTopley Oui, mais ça marche. ;)
trusktr

0

Pour les constantes, Enum est un meilleur choix à mon humble avis. Voici un exemple

classe publique myClass {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}

0

L'une des façons dont je le fais est de créer une classe «globale» avec les valeurs constantes et d'effectuer une importation statique dans les classes qui ont besoin d'accéder à la constante.


0

static finalest ma préférence, je n'utiliserais un enumsi l'article était en effet énumérable.


0

j'utilise static final pour déclarer des constantes et aller avec la notation de nommage ALL_CAPS. J'ai vu pas mal d'instances réelles où toutes les constantes sont regroupées dans une interface. Quelques articles ont à juste titre qualifié cela de mauvaise pratique, principalement parce que ce n'est pas le rôle d'une interface. Une interface doit appliquer un contrat et ne doit pas être un endroit pour insérer des constantes non liées. Le regrouper dans une classe qui ne peut pas être instanciée (via un constructeur privé) est également très bien si la sémantique constante n'appartient pas à une classe spécifique ( es). Je mets toujours une constante dans la classe à laquelle elle est la plus liée, car cela a du sens et est également facilement maintenable.

Les énumérations sont un bon choix pour représenter une plage de valeurs, mais si vous stockez des constantes autonomes en mettant l'accent sur la valeur absolue (par exemple TIMEOUT = 100 ms), vous pouvez simplement opter pour l' static finalapproche.


0

Je suis d'accord avec ce que la plupart disent, il est préférable d'utiliser des énumérations lorsqu'il s'agit d'une collection de constantes. Cependant, si vous programmez sous Android, il existe une meilleure solution: IntDef Annotation .

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

L'annotation IntDef est supérieure aux énumérations d'une manière simple, elle prend beaucoup moins de place car elle est simplement un marqueur de compilation. Ce n'est pas une classe, ni la propriété de conversion de chaîne automatique.


Bien que je sois d'accord avec la meilleure pratique de ne pas utiliser l'interface en Java seul et d'éviter l'énumération dans Android, ce remplacement dans Android ne fonctionne que lorsque vous utilisez un petit nombre de champs. Il s'agit d'une économie de mémoire importante, mais peut entraîner des ballonnements car vous êtes interface par champ dans une énumération mixte. Par exemple, si j'ai une énumération mixte qui définit ce qu'un objet prend dans son constructeur, je ne peux rien enregistrer avec cette approche et je reviens aux constantes non sécurisées car, sous Android, vous ne voulez pas trop de périodes classes / interfaces.
Droid Teahouse

0

C'est une mauvaise habitude et une pratique terriblement ennuyeuse de citer Joshua Bloch sans comprendre le fondamentalisme fondamental zéro.

Je n'ai rien lu Joshua Bloch, donc soit

  • c'est un terrible programmeur
  • ou les gens jusqu'à présent que je trouve en le citant (Joshua est le nom d'un garçon que je présume) utilisent simplement son matériel comme scripts religieux pour justifier leurs indulgences religieuses logicielles.

Comme dans l'intégrisme biblique, toutes les lois bibliques peuvent être résumées par

  • Aimez l'identité fondamentale de tout votre cœur et de tout votre esprit
  • Aime ton prochain comme toi-même

et de même le fondamentalisme du génie logiciel peut être résumé par

  • consacrez-vous aux principes fondamentaux de zéro avec toute votre puissance de programmation et votre esprit
  • et consacrez à l'excellence de vos collègues programmeurs comme vous le feriez pour vous-même.

De plus, parmi les cercles fondamentalistes bibliques, un corollaire fort et raisonnable est établi

  • D'abord aime toi. Parce que si vous ne vous aimez pas beaucoup, le concept "aimez votre prochain comme vous-même" n'a pas beaucoup de poids, car "combien vous vous aimez" est la ligne de référence au-dessus de laquelle vous aimeriez les autres.

De même, si vous ne vous respectez pas en tant que programmeur et acceptez simplement les déclarations et les prophéties de certains gourous de la programmation SANS remettre en question les principes fondamentaux, vos citations et votre confiance en Joshua Bloch (et autres) n'ont aucun sens. Et par conséquent, vous n'auriez en fait aucun respect pour vos collègues programmeurs.

Les lois fondamentales de la programmation logicielle

  • la paresse est la vertu d'un bon programmeur
  • vous devez rendre votre vie de programmation aussi simple, paresseuse et donc aussi efficace que possible
  • vous devez rendre les conséquences et les entrailles de votre programmation aussi simples, paresseuses et donc aussi efficaces que possible pour vos voisins-programmeurs qui travaillent avec vous et ramassent vos entrailles de programmation.

Les constantes de modèle d'interface sont une mauvaise habitude ???

En vertu de quelles lois de programmation fondamentalement efficace et responsable tombe cet édit religieux?

Lisez simplement l'article de wikipedia sur les constantes de modèle d'interface ( https://en.wikipedia.org/wiki/Constant_interface ), et les excuses idiotes qu'il énonce contre les constantes de modèle d'interface.

  • Whatif-No IDE? Qui sur terre en tant que programmeur logiciel n'utiliserait pas un IDE? La plupart d'entre nous sont des programmeurs qui préfèrent ne pas avoir à prouver leur survie au machisme aescétique en évitant l'utilisation d'un IDE.

    • Aussi - attendez un deuxième partisan de la programmation micro-fonctionnelle pour ne pas avoir besoin d'un IDE. Attendez d'avoir lu mon explication sur la normalisation du modèle de données.
  • Pollue l'espace de noms avec des variables non utilisées dans la portée actuelle? Il pourrait être partisan de cette opinion

    • ne sont pas conscients de la normalisation du modèle de données et de la nécessité
  • L'utilisation d'interfaces pour appliquer des constantes est un abus d'interfaces. Ses partisans ont la mauvaise habitude de

    • ne pas voir que les "constantes" doivent être traitées comme des contrats. Et les interfaces sont utilisées pour appliquer ou projeter la conformité à un contrat.
  • Il est difficile, voire impossible, de convertir des interfaces en classes implémentées à l'avenir. Hah .... hmmm ... ???

    • Pourquoi voudriez-vous vous engager dans un modèle de programmation comme votre subsistance persistante? IOW, pourquoi vous consacrer à une telle habitude de programmation AMBIVALENTE et mauvaise?

Quelles que soient les excuses, il n’existe AUCUNE EXCUSE VALABLE en matière de génie logiciel FONDAMENTALEMENT EFFICACE pour délégitimer ou décourager généralement l’utilisation de constantes d’interface.

Peu importe les intentions et les états mentaux d'origine des pères fondateurs qui ont élaboré la Constitution des États-Unis. Nous pourrions débattre des intentions originales des pères fondateurs, mais tout ce qui m'importe, ce sont les déclarations écrites de la Constitution américaine. Et il est de la responsabilité de chaque citoyen américain d'exploiter l'intégrisme littéraire écrit, et non les intentions fondatrices non écrites, de la Constitution américaine.

De même, je me fiche de ce que les intentions "originales" des fondateurs de la plate-forme Java et du langage de programmation avaient pour l'interface. Ce qui m'importe, ce sont les fonctionnalités efficaces fournies par la spécification Java, et j'ai l'intention d'exploiter ces fonctionnalités au maximum pour m'aider à respecter les lois fondamentales de la programmation logicielle responsable. Peu m'importe si je suis perçu comme "violant l'intention des interfaces". Peu m'importe ce que Gosling ou quelqu'un Bloch dit à propos de la "bonne façon d'utiliser Java", à moins que ce qu'ils disent ne viole pas mon besoin de fondamentaux épanouissants et EFFICACES.

L'essentiel est la normalisation du modèle de données

Peu importe comment votre modèle de données est hébergé ou transmis. Que vous utilisiez des interfaces ou des énumérations ou des whatevernots, relationnels ou sans SQL, si vous ne comprenez pas le besoin et le processus de normalisation du modèle de données.

Nous devons d'abord définir et normaliser le modèle de données d'un ensemble de processus. Et lorsque nous avons un modèle de données cohérent, SEULEMENT alors nous pouvons utiliser le flux de processus de ses composants pour définir le comportement fonctionnel et le processus bloque un champ ou un domaine d'applications. Et c'est seulement alors que nous pourrons définir l'API de chaque processus fonctionnel.

Même les facettes de la normalisation des données telles que proposées par EF Codd sont maintenant sérieusement mises à l'épreuve et sévèrement mises à l'épreuve. Par exemple, sa déclaration sur 1NF a été critiquée comme ambiguë, mal alignée et trop simplifiée, tout comme le reste de ses déclarations, en particulier avec l'avènement des services de données modernes, des technologies de prise en charge et de la transmission. OMI, les déclarations EF Codd devraient être complètement abandonnées et un nouvel ensemble de déclarations plus plausibles mathématiquement devrait être conçu.

Une faille flagrante d'EF Codd et la cause de son mauvais alignement sur une compréhension humaine efficace est sa conviction que les données multidimensionnelles et mutables perceptibles humainement peuvent être efficacement perçues à travers un ensemble de mappages bidimensionnels fragmentaires.

Les fondements de la normalisation des données

Ce qu'EF Codd n'a pas exprimé.

Au sein de chaque modèle de données cohérent, il s'agit de l'ordre séquentiel gradué de cohérence du modèle de données à atteindre.

  1. L'unité et l'identité des instances de données.
    • concevoir la granularité de chaque composant de données, leur granularité étant à un niveau où chaque instance d'un composant peut être identifiée et récupérée de manière unique.
    • absence d'aliasing d'instance. c'est-à-dire qu'il n'existe aucun moyen par lequel une identification produit plus d'une instance d'un composant.
  2. Absence de diaphonie d'instance. Il n'existe pas la nécessité d'utiliser une ou plusieurs autres instances d'un composant pour contribuer à l'identification d'une instance d'un composant.
  3. L'unité et l'identité des composants / dimensions des données.
    • Présence de détournement de composants. Il doit exister une définition permettant d'identifier un composant / une dimension de manière unique. Quelle est la définition principale d'un composant;
    • où la définition principale n'entraînera pas l'exposition de sous-dimensions ou de composants membres qui ne font pas partie d'un composant prévu;
  4. Moyen unique de désaliasage des composants. Il doit exister une et une seule définition de suppression d'alias pour un composant.
  5. Il existe une et une seule interface de définition ou contrat pour identifier un composant parent dans une relation hiérarchique de composants.
  6. Absence de diaphonie des composants. Il n'existe pas la nécessité d'utiliser un membre d'un autre composant pour contribuer à l'identification définitive d'un composant.
    • Dans une telle relation parent-enfant, la définition d'identification d'un parent ne doit pas dépendre d'une partie de l'ensemble des composants membres d'un enfant. Un élément membre de l'identité d'un parent doit être l'identité complète de l'enfant sans recourir à la référence à tout ou partie des enfants d'un enfant.
  7. Préempter les apparences bimodales ou multimodales d'un modèle de données.
    • Lorsqu'il existe deux définitions candidates d'un composant, c'est un signe évident qu'il existe deux modèles de données différents mélangés en un seul. Cela signifie qu'il y a incohérence au niveau du modèle de données ou au niveau du champ.
    • Un domaine d'applications doit utiliser un et un seul modèle de données, de manière cohérente.
  8. Détecter et identifier la mutation des composants. À moins que vous n'ayez effectué une analyse statistique des composants d'énormes données, vous ne voyez probablement pas, ou ne voyez pas la nécessité de traiter, la mutation des composants.
    • Un modèle de données peut voir certaines de ses composantes muter cycliquement ou progressivement.
    • Le mode peut être rotation-membre ou rotation-transposition.
    • La mutation de rotation des membres pourrait être un échange distinct de composants enfants entre les composants. Ou où des composants complètement nouveaux devraient être définis.
    • La mutation transpositionnelle se manifesterait comme un membre dimensionnel muter en un attribut, vice versa.
    • Chaque cycle de mutation doit être identifié comme un modal de données distinct.
  9. Mettez à jour chaque mutation. Telle que vous pouvez extraire une version précédente du modèle de données, lorsque peut-être le besoin se fait sentir de traiter une mutation de 8 ans du modèle de données.

Dans un domaine ou une grille d'applications de composants inter-services, il doit y avoir un et un seul modèle de données cohérent ou il existe un moyen pour un modèle / version de données de s'identifier.

Demandons-nous toujours si nous pourrions utiliser des constantes d'interface? Vraiment ?

Des problèmes de normalisation des données sont en jeu plus importants que cette question banale. SI vous ne résolvez pas ces problèmes, la confusion que vous pensez que les constantes d'interface provoquent n'est comparativement rien. Rien.

À partir de la normalisation du modèle de données, vous déterminez les composants en tant que variables, propriétés, constantes d'interface de contrat.

Ensuite, vous déterminez ce qui entre dans l'injection de valeur, la conservation de la configuration des propriétés, les interfaces, les chaînes finales, etc.

Si vous devez utiliser l'excuse de devoir localiser un composant plus facilement à dicter par rapport aux constantes d'interface, cela signifie que vous avez la mauvaise habitude de ne pas pratiquer la normalisation du modèle de données.

Vous souhaitez peut-être compiler le modèle de données dans une version vcs. Que vous pouvez extraire une version distinctement identifiable d'un modèle de données.

Les valeurs définies dans les interfaces sont totalement assurées d'être non modifiables. Et partageable. Pourquoi charger un ensemble de chaînes finales dans votre classe à partir d'une autre classe alors que tout ce dont vous avez besoin est cet ensemble de constantes ??

Alors pourquoi ne pas publier un contrat de modèle de données? Je veux dire si vous pouvez le gérer et le normaliser de manière cohérente, pourquoi pas? ...

public interface CustomerService {
  public interface Label{
    char AssignmentCharacter = ':';
    public interface Address{
      String Street = "Street";
      String Unit= "Unit/Suite";
      String Municipal = "City";
      String County = "County";
      String Provincial = "State";
      String PostalCode = "Zip"
    }

    public interface Person {
      public interface NameParts{
        String Given = "First/Given name"
        String Auxiliary = "Middle initial"
        String Family = "Last name"
      }
    }
  }
}

Maintenant, je peux référencer les libellés contractés de mes applications de manière telle que

CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family

Cela confond le contenu du fichier jar? En tant que programmeur Java, je ne me soucie pas de la structure du pot.

Cela présente de la complexité pour les échanges d'exécution motivés par osgi? Osgi est un moyen extrêmement efficace pour permettre aux programmeurs de continuer dans leurs mauvaises habitudes. Il existe de meilleures alternatives que l'osgi.

Ou pourquoi pas ça? Il n'y a aucune fuite des constantes privées dans le contrat publié. Toutes les constantes privées doivent être regroupées dans une interface privée nommée "Constantes", car je ne veux pas avoir à rechercher de constantes et je suis trop paresseux pour taper à plusieurs reprises "chaîne finale privée".

public class PurchaseRequest {
  private interface Constants{
    String INTERESTINGName = "Interesting Name";
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

Peut-être même ceci:

public interface PurchaseOrderConstants {
  public interface Properties{
    default String InterestingName(){
       return something();
    }
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

Le seul problème avec les constantes d'interface mérite d'être pris en compte, c'est quand l'interface est implémentée.

Ce n'est pas "l'intention originale" des interfaces? Comme si je me soucierais de "l'intention originale" des pères fondateurs dans l'élaboration de la Constitution américaine, plutôt que de la façon dont la Cour suprême interpréterait les lettres écrites de la Constitution américaine ???

Après tout, je vis au pays du libre, du sauvage et de la maison des braves. Soyez courageux, libre, sauvage, utilisez l'interface. Si mes collègues programmeurs refusent d'utiliser des moyens de programmation efficaces et paresseux, suis-je obligé par la règle d'or de réduire mon efficacité de programmation pour l'aligner avec la leur? Je devrais peut-être le faire, mais ce n'est pas une situation idéale.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.