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.