Utiliser des énumérations pour les index de tableau en Java
Lors de la lecture de Java efficace, je suis tombé sur la suggestion d ' "utiliser des énumérations au lieu des constantes int
". Dans un projet en cours, je fais quelque chose de similaire à celui ci-dessous:
int COL_NAME = 0;
int COL_SURNAME = 1;
table[COL_NAME] = "JONES"
Comment devrais-je utiliser enums à la place pour y parvenir? En raison de l'interface que je suis obligé d'utiliser, je dois utiliser un int
pour mon index. L'exemple ci-dessus est juste un exemple. J'utilise en fait une API qui prend un int
pour les valeurs d'index.
7 réponses
L'application d'un motif utile avec un anti-motif échoue souvent ; -)
Dans votre cas, l'utilisation d'un tableau pour des données pas vraiment de type tableau pose un problème lorsque vous souhaitez remplacer les constantes int
par des valeurs enum
.
Propre(re) solution serait quelque chose comme un EnumMap
avec le enum
valeurs clés.
, vous pouvez également utiliser table[COL_NAME.ordinal()]
si vous devez absolument.
Si une API vous force à passer des valeurs int
mais que vous avoir le contrôle sur les valeurs réelles (c'est-à-dire que vous pouvez passer vos propres constantes), alors vous pouvez passer à l'utilisation des valeurs enum
dans votre code et convertir vers/depuis enum
uniquement aux endroits où votre code s'interface avec L'API. L'opération inverse de enumValue.ordinal()
est EnumClass.values()[ordinal]
).
On dirait que vous essayez d'utiliser un EnumMap. Ceci est une carte qui enveloppe un tableau de valeurs.
enum Column {
NAME, SURNAME
}
Map<Column, String> table = new EnumMap<Column, String>(Column.class);
table.put(Column.NAME, "JONES");
String name = table.get(Column.NAME);
Ce serait beaucoup plus simple si vous utilisiez un POJO.
classPerson {
String name;
String surname;
}
Person person = new Person();
person.name = "JONES";
String name = person.name;
Dépend des exigences. Vous pouvez utiliser Enum.ordinal()
pour convertir une énumération en int.
Notez qu'il n'est pas possible de passer une énumération directement en tant qu'index.
Modifier:
Une Autre possibilité serait d'utiliser un Map<YourEnum, String> map
, puis utiliser map.get(EnumValue)
.
Puisque vous devez utiliser cette table et ne pouvez donc pas utiliser un EnumMap
, Je pense personnellement que la meilleure solution serait de rester avec ce que vous avez. Dans une énumération, les valeurs ordinales des éléments ne sont pas censées avoir une signification intrinsèque, alors que dans votre cas elles le font, puisqu'elles sont utilisées comme indices dans la table.
Le problème que vous avez n'est pas que vous n'utilisez pas d'énumérations, c'est que vous avez besoin de valeurs magiques pour extraire les données de colonne d'une table. Dans ce cas, en utilisant integer constantes est le bon outil pour le travail, sauf si vous pouvez résoudre le problème sous-jacent de cette table.
Maintenant, vous pouvez l'aborder en enveloppant la table dans votre propre classe qui y accède, et utiliser des énumérations Dans et hors de cette classe. Mais cela introduit plus de code, une autre couche d'indirection et ne résout aucun problème pour vous, sauf qu'une énumération est un peu plus facile à maintenir qu'une liste de valeurs int (grandement compensée par le fait que vous devez maintenir le wrapper que vous avez maintenant écrit).
Vous pouvez considérer ce travail si vous écrivez une API publique que d'autres personnes utiliseront, car cela évitera de les faire dépendre de certaines valeurs magiques qui pourraient changer avec le temps (couplage serré qui va casser les choses). Si vous l'êtes, alors un wrapper qui utilise un EnumMap
en interne est probablement le chemin à parcourir.
Sinon, laissez-le tel quel.
En fonction des valeurs de votre tableau, vous pouvez regarder un objet à la place. Pour des exemples si votre tableau ressemble à ceci
person[FIRST_NAME] = "Jim Bob"
person[SURNAME] = "Jones"
person[ADDRESS] = "123 ABC St"
person[CITY] = "Pleasantville"
...
Alors ce que vous voulez vraiment, c'est quelque chose comme ça
Person jimBob = new Person("Jim Bob", "Jones");
jimBob.setAddress("123 ABC St", "Pleasantville", "SC");
....
J'ai aussi rencontré ce problème, et étant venu du monde c++, Je ne m'attendais pas à rencontrer cela.
La beauté d'enum est que peut créer une série de constantes associées avec des valeurs uniques où la valeur réelle n'est pas pertinente. Leur utilisation rend le code plus facile à lire et empêche les variables d'être définies sur des valeurs enum invalides (en particulier en Java), mais dans une situation comme celle-ci, c'est une douleur majeure. Alors que vous pourriez avoir "animaux enum {chat, oiseau, chien}" et ne se soucient pas vraiment quelle valeur le chat, L'oiseau et le chien représentent réellement, c'est tellement agréable et propre à écrire: myPets[CHAT] = "Dexter"; myPets [oiseau] = " Polly"; MyPets [chien] = "Boo-Rooh";
Dans Ma situation, j'ai fini par écrire une fonction de conversion où vous passez une valeur enum et je retourne une constante. Je déteste faire cela avec passion, mais c'est le seul moyen propre que je connaisse pour maintenir la commodité et la vérification des erreurs d'enum.
private int getPetsValue(Pets inPet) {
int value = 0;
switch (inPet) {
case CAT: value = 0; break;
case BIRD: value = 1; break;
case DOG: value = 2; break;
default:
assert(false);
value = 0;
break;
}
return value;
}
, Vous pouvez définir un enum
avec un constructeur comme suit:
public enum ArrayIndex {
COL_NAME(0), COL_SURNAME(1);
private int index;
private ArrayIndex(int index) {
this.index = index;
}
public int getIndex() {
return this.index;
}
};
Et puis utilisez-le comme ceci:
public static void main (String args[]) {
System.out.println("index of COL_NAME is " + ArrayIndex.COL_NAME.getIndex());
}