Variantes d'énumérations en Java
-
Besoin
- Définir un nombre fixé (non extensible dynamiquement) de constantes
-
Solutions envisageables
-
Solution universelle (adaptable pour tout langage) : définir des variables globales entières immutables
- En Java : champs static final int dans une classe (par convention, nom en MAJUSCULES)
-
Utiliser des constantes instances d'une classe (pas des int)
- Employer une classe Enum (possible depuis Java 1.5)
-
Solution universelle (adaptable pour tout langage) : définir des variables globales entières immutables
Solution 1 : des constantes entières
public class Bulb { public static final int SWITCHED_OFF = 0; public static final int SWITCHED_ON = 1; public static final int BROKEN = 2; private int state; ... public int getState() { return state; } public boolean isFaulty() { return state == BROKEN; } public boolean isLighting() { return state == SWITCHED_ON; } }
-
Ajout d'un état SWITCHED_DIM (éclairage tamisé) ?
- Réécriture de isLighting()
-
Disjonction de BROKEN en WORN et DISABLED ?
- Réécriture de isFaulty()
- isLighting() et isFaulty() sont des caractéristiques de l'état de l'ampoule et non de l'ampoule elle-même
Solution 2 : des instances d'une classe BulbState
package fr.upem.jacosa.safety; public class BulbState { private final boolean lighting; private final boolean faulty; public BulbState(boolean lighting, boolean faulty) { this.lighting = lighting; this.faulty = faulty; } public boolean isLighting() { return lighting; } public boolean isFaulty() { return faulty; } public static final BulbState SWITCHED_OFF = new BulbState(false, false); public static final BulbState SWITCHED_ON_FULL = new BulbState(true, false); public static final BulbState SWITCHED_ON_DIM = new BulbState(true, false); public static final BulbState WORN = new BulbState(false, true); public static final BulbState DISABLED = new BulbState(false, true); }
Allumons l'ampoule
public class Bulb { ... private BulbState state; public void switchBulb() { if (state == BulbState.SWITCHED_OFF) { if (overCurrent()) state = BulbState.DISABLED; else if (tooOld()) state = BulbState.WORN; else if (dimming()) state = BulbState.SWITCHED_ON_DIM; else state = BulbState.SWITCHED_ON_FULL; } else if (state == BulbState.WORN) throw new IllegalStateException("The bulb is worn, please replace it!"); else if (state.isLighting()) state = BulbState.SWITCHED_OFF; } }
- Problème : on n'a pas traité le cas BulbState.DISABLED !
- Mais ça ne gène pas le compilateur (le nombre d'instances de BulbState n'est pas borné).
Solution 3 : une classe Enum
package fr.upem.jacosa.safety; public enum BulbStateEnum { SWITCHED_OFF(false, false), SWITCHED_ON_FULL(true, false), SWITCHED_ON_DIM(true, false), WORN(false, true), DISABLED(false, true); private final boolean lighting; private final boolean faulty; BulbStateEnum(boolean lighting, boolean faulty) { this.lighting = lighting; this.faulty = faulty; } public boolean isLighting() { return lighting; } public boolean isFaulty() { return faulty; } }
Réecrivons le switch... avec un switch
public class Bulb { ... private BulbStateEnum state; public void switchBulb() { switch (state) { case BulbState.SWITCHED_OFF: if (overCurrent()) state = BulbState.DISABLED; else if (tooOld()) state = BulbState.WORN; else if (dimming()) state = BulbState.SWITCHED_ON_DIM; else state = BulbState.SWITCHED_ON_FULL; break; case BulbState.WORN: throw new IllegalStateException("The bulb is worn, please replace it!"); case BulbState.SWITCHED_ON_FULL: case BulbState.SWITCHED_ON_DIM: case BulbState.DISABLED: state = BulbState.SWITCHED_OFF; break; default: // To manage other states not addressed in a case } } public BulbState getState() { return state; } public boolean isLighting() { return state.isLighting(); } public boolean isFaulty() { return state.isFaulty(); } }
Quelques méthodes sur les Enum
- int ordinal() : pour obtenir l'ordre de déclaration d'une constante (SWITCHED_OFF == 0, SWITCHED_ON_FULL == 1...) ;
- ne doit pas être utilisé pour la sérialisation (car des constantes supplémentaires peuvent être ajoutées au milieu d'un Enum)
- String name() : nom de la constante (utilisable par exemple pour l'affichage)
- static Enum valueOf(String s) : permet d'obtenir une constante par son nom (retourne null si aucune constante ne correspond)
- Enum[] values() : retourne un tableau de toutes les constantes définies
Le tri des ampoules
Voici une liste d'ampoules : List<Bulb> bulbList.
Comment trier les ampoules selon leur état ?
En utilisant une EnumMap :
EnumMap<BulbState, List<Bulb>> map = new EnumMap<BulbState, List<Bulb>>(); for (Bulb bulb: bulbList) { List<Bulb> subList = map.get(bulb.getState()); if (subList == null) { // It is the first bulb that matches this state subList = new ArrayList<Bulb>(); map.put(bulb.getState(), subList); } subList.add(bulb); }
Remarque : il existe également EnumSet.