2009-09-03 13 views
26

Si j'ai une collection de constantes statiques que je veux déclarer de façon centralisée afin qu'elles puissent être partagées entre divers projets si elles sont placées dans une classe ou une interface (Java). Dans le passé, je les ai vus la plupart du temps mis dans une classe mais j'ai commencé à penser que puisque la classe ne devrait pas être instanciée, peut-être qu'ils seraient mieux dans une interface, mais encore une fois l'interface ne devrait pas être implémentée toutes les classes, par exempleUne collection de constantes doit-elle être placée dans une classe ou une interface?

public class ErrorCodes { 
    public static final String ERROR_1 = "-1"; 
    public static final String ERROR_2 = "-2"; 
} 

ou

public interface ErrorCodes { 
    public static final String ERROR_1 = "-1"; 
    public static final String ERROR_2 = "-2"; 
} 

Répondre

27

Si elles ont des liens solides, alors je les mettre dans un ENUM:

public enum Error { 
    ERROR_1("-1", "foo went wrong"), 
    ERROR_2("-2", "bar went wrong"); 

    private final String id; 
    private final String message; 

    Error(String id, String message) { 
    this.id=id; 
    this.message=message; 
    } 

    public String getId() { 
    return id; 
    } 

    public String getMessage() { 
    return message; 
    } 
} 

L'avantage est que vous pouvez avoir la sécurité de type dans votre code et que vous pouvez facilement ajouter une recherche basée sur l'identifiant (soit en construisant un HashMap<String,Error> dans le constructeur ou simplement en bouclant sur values()).

+0

Une énumération est en fait une meilleure façon de procéder. Je suppose que je n'ai pas lu sa question assez attentivement pour comprendre ses intentions ... –

+1

J'ai trouvé que c'était la meilleure solution, car vous pouvez garder les nombres et les chaînes ensemble et charger les chaînes à partir d'un fichier de propriétés. Tout en un seul endroit. –

+0

Est-ce toujours la meilleure approche si vous avez une grande quantité de constantes ou si elle affecte la performance après un certain point? – Yonetmen

4

Vous devriez le faire dans une classe. Une interface est une description des méthodes disponibles, des propriétés auxquelles les utilisateurs de classe peuvent accéder - en implémentant une interface, vous garantissez que les membres déclarés dans l'interface sont disponibles pour l'utilisateur. D'autre part, une classe, est une description d'un objet ou (si vous n'êtes pas trop dur sur les principes OO ...) un espace réservé pour les membres statiques. Personnellement, je trouve très utile dans certains projets de stocker un tas de constantes dans une classe Settings, donc je n'ai pas besoin de regarder dans le projet entier pour les définitions. Je pense que cette approche est aussi ce que vous recherchez.

+0

Collectez vos constantes dans une classe et attribuez-lui un constructeur privé pour éviter qu'elles soient instanciées. –

5

L'utilisation de static import devraient être considérés ici (pour les constantes importation définies dans une classe), ou type-safe Enum.

De Interface for constants

constantes Mise en place dans une interface est une technique populaire dans les premiers jours de Java, mais maintenant beaucoup le considèrent comme une utilisation de mauvais goût d'interfaces, car interfaces doivent faire face aux services fournis par un objet, pas ses données.
De plus, les constantes utilisées par une classe sont généralement un détail d'implémentation, mais les placer dans une interface les promeut dans l'API publique de la classe.

2

Vous devez les mettre dans la classe avec un constructeur privé.

public class ErrorCodes { 
    private ErrorCodes() {} // prevents instantiation 
    public static final String ERROR_1 = "-1"; 
    public static final String ERROR_2 = "-2"; 

}

Ou mieux encore, utilisez un enum typesafe.

5

Cela a été discuté before:

La raison pour laquelle vous ne voulez pas les constantes dans une interface est qu'il incite les classes client à « mettre en œuvre » cette interface (pour accéder aux constantes sans préfixer avec le nom de l'interface). Vous ne devriez pas, cependant - l'interface n'est pas réellement une interface aux capacités de l'objet, mais une commodité de compilation intégrée dans le type externe de la classe.

Il fut un temps où « l'interface constante » était très pratique, mais il a toujours été « mauvais » et même pas la paresse est une excuse pour l'utiliser maintenant que nous avons import static déclarations.

Éditer: Bien que je doive convenir que pour le scénario présenté dans votre question, les enums sont plus appropriés.

7

Certaines personnes considèrent une interface constante comme un anti-modèle (http://en.wikipedia.org/wiki/Constant_interface).

+4

Pour moi, l'anti-pattern est * l'implémentation * d'une interface pour avoir accès aux constantes nommées. –

0

Personnellement, je pense que les constantes doivent être définies dans une classe pour les mêmes raisons que celles décrites ci-dessus. Surtout parce que certains développeurs utilisent ces constantes en implémentant l'interface dans la classe qui veut les utiliser. Quand cette interface contient beaucoup de constantes, vous ne voulez plus regarder le javadoc de cette classe spécifique car il est jonché de descriptions de constantes qui ne sont probablement même pas utilisées par cette classe.

2

Je recommande une combinaison d'importations statiques et d'interfaces pour les constantes.

Si une interface Java a des déclarations de champ constant, gardez à l'esprit que ce sont implicitement publique, statique et final (voir la spécification du langage Java, Section 9.3.) Vous pouvez donc omettre toujours ces modificateurs, ne laissant que le type, et votre interface constante ressemblerait à ceci:

public interface Constants { 
    int AGE = 0x23; 
    String NAME = "Andrew"; 
    boolean IGNORE = true; 
} 

cela devrait, bien sûr, ne jamais être utilisé comme suit:

import static Constants.*; 

public Whatever { 
    public String method() { 
     return String.format("%s is %d%c", NAME, AGE, IGNORE ? '?' : '!'); 
    } 
} 

Je n'ai aucun problème à utiliser ce style dans mon code de production, et je pense que cela conduit à une collection de constantes compactes et très soignées, et que je peux faire face à différents types de constantes, impossibles à remplir et pouvant être étendues si requred, contrairement à une énumération.

Une autre possibilité, que tout le monde n'approuvera pas, consiste à imbriquer des interfaces (ou même des types enum) dans votre interface parent, ce qui vous permet de grouper vos constantes. Ce:

interface MoreConstants { 
    int MAGIC = 0xCAFEBABE; 
    interface PROPERTIES { 
     String NAME = "name"; 
    } 
    enum ERRORS { 
     ON_FIRE, ASLEEP, BROKEN, UNSURE; 
    } 
} 

et les accès comme celui-ci, en supposant une importation statique des MoreConstants Interface:

if (!PROPERTIES.NAME.equals(value)) { 
    return ERRORS.UNSURE; 
} 

Bien sûr, ces interfaces ne doivent jamais être mises en œuvre, que je considérerais une mauvaise pratique. La seule façon d'assurer cela, cependant, est d'effectuer des revues de code strictes ...

+0

Un problème que vous ne touchez pas est que certaines constantes seront copiées au moment de la compilation dans le bytecode généré au lieu d'être référencées, vous laissant avec un ABI que vous ne pouvez pas changer sans casser les choses. –

+0

Cela ne pose-t-il pas également un problème avec la solution 'class for constants', en raison de l'accès direct aux champs? – grkvlt

+0

Oui, je pense que la même chose se passe à la fois pour la classe et l'interface, mais je peux me tromper. +1 aux réponses enum –

Questions connexes