2017-04-11 1 views
1

Je fais face à certains travaux concernant des endroits où j'ai utilisé des représentations de chaîne ou int intempestives de partie du modèle, et en utilisant Enum et EnumSet les meilleures pratiques.Meilleure initialisation pour un EnumSet <E> maintenu par l'instance de E

Une difficulté particulière est ce cas d'utilisation: un Enum où chaque instance est titulaire d'un EnumSet de [0..n] de ses propres sœurs.

Pour dépouiller à l'essentiel ma question que je reposeront sur StyleEnum de Joshua Bloch. Nous avons donc une enum de BOLD, ITALIQUE, UNDERLINE, STRIKETHROUGH .. et imaginons un B_AND_I qui tiendra {BOLD, ITALIC}.

S'il vous plaît, ne prenez pas beaucoup de sens l'exemple: dans le système réel c'est construit sur des sous-ensembles de base de certaines règles changeantes chargées @ temps de démarrage.

L'objectif est qu'une fois que ce calcul a eu lieu, rien ne peut changer par exemple gamme sous-EnumSet particulier. Alors je viens avec quelque chose comme ceci:

public enum StyleEnum { 
    NONE(0, "none"), BOLD(100, "B"), ITALIC(250, "i"), UNDERLINE(350, "u"), STRIKETHROUGH(9, "b"), B_AND_I(99,"Emphase"); 

//// Pure dream == private final EnumSet<StyleEnum> complexComputedSubSet = new EnumSet<StyleEnum>(); 
//// But not in the jdk 
    private final EnumSet<StyleEnum> complexComputedSubSet; 
    private final int intProp; 
    private final String strLabel; 

    StyleEnum(int intProp, String strLabel) { 
     this.intProp = intProp; 
     this.strLabel = strLabel; 
//// option 2 would have been be this   
//  complexComputedSubSet = EnumSet.of(NONE); 
//// But COMPILER :: illegal reference to static field from initializer 

    }//.... end of constructor 


    /** 
    * static initialzer will compute based on some rules a subset of (none) or 
    * others Enum, a particular enum instance can holds in his bag. 
    */ 
    static { 
//// at least, as option 3, why not this...   
//  for (StyleEnum e : EnumSet.allOf(StyleEnum.class)) { 
//   e.complexComputedSubSet = EnumSet.of(NONE); 
//  } 
//// COMPILER :: cannot assign a value to final variable complexComputedSubSet 

     // main handling here : at class loading 
     // compute a set (rules coming from whatever you want or can). 
     //Once this static class level init is done 
     // nothing can change the computed EnumSet 
     // it's getter will always return an unmodifiable computed EnumSet 
     //.... computing something 
    } 


    //.... 
    //getter(){} 
    //whateverelse(){} 

} 

Comme vous pouvez le voir rien est vraiment agréable ou tout au moins élégant ici.

Dans mes rêves:

private final EnumSet<StyleEnum> complexComputedSubSet= new EnumSet<StyleEnum>(); 
//.. 
//static initialzer 
static { 
    EnumSet.allOf(StyleEnum.class).forEach(e-> computeSubSet(e)); 
//.. 
} 
private static void computeSubSet(StyleEnum instance){ 
    //... 
    instance.complexComputedSubSet.addAll(someComputedCollection); 
} 

Et voilà!

Au lieu de cela, tout ce que je peux faire semble éloigner la finale sur le terrain

// getting away from the final keyword 
private EnumSet<StyleEnum> complexComputedSubSet; 

puis dans la boucle de bloc initialiseur statique theClass et instancier avec le marqueur (factice) (NONE) introduite seulement pour ce (stupide) but:

 for (StyleEnum e : EnumSet.allOf(StyleEnum.class)) { 
      e.complexComputedSubSet = EnumSet.of(NONE); 
     } 

Et seulement après cela calculer et stocker le sous-EnumSet.

Alors toute cette douleur, -mostly-, juste parce que l'on ne peut pas dire « nouvelle EnumSet(); » ? Il doit y avoir un meilleur moyen? Pouvez-vous s'il vous plaît me diriger vers la bonne direction?

+0

Ne devrait pas 'e.complexComputedSubSet = EnumSet.copyOf (someComputedCollection);' être suffisant? Vous devez toujours supprimer le mot clé 'final' mais cela ne devrait pas faire de mal. – Thomas

+0

BTW, je pense que 'EnumSet.noneOf (StyleEnum.class)' doit être équivalente à la 'nouvelle EnumSet (); Vous êtes après. Les états JavaDoc: "Crée un ensemble d'énumération vide avec le type d'élément spécifié." - Ce nom de méthode est très regrettable que :) – Thomas

+0

Ce fut l'un de mes premiers vraiment attemps: 'privé EnumSet complexComputedSubSet = EnumSet.noneOf (StyleEnum.class);' \t mais cette ligne mignonne résout dans cette trace effrayant : \t ** 'causée par: java.lang.ClassCastException: classe entity.StyleEnum pas enum' ** ' à java.util.EnumSet.noneOf (EnumSet.java:112) '' à entity.StyleEnum. (StyleEnum.java:22) ' ' at entity.StyleEnum. (StyleEnum.java: 5) ' \t Je viens donc de quitter son utilisation. –

Répondre

0

J'abandonner maintenant le groupe auxiliaire dans un champ d'instance, et au lieu de mettre en œuvre comme une carte statique:

import java.util.Collections; 
import java.util.Map; 
import java.util.Set; 
import java.util.EnumMap; 
import java.util.EnumSet; 

public enum StyleEnum { 
    NONE(0, "none"), 
    BOLD(100, "B"), 
    ITALIC(250, "i"), 
    UNDERLINE(350, "u"), 
    STRIKETHROUGH(9, "b"), 
    B_AND_I(99,"Emphase"); 

    private static Map<StyleEnum, Set<StyleEnum>> complexSubsets; 

    private final int intProp; 
    private final String strLabel; 

    StyleEnum(int intProp, String strLabel) { 
     this.intProp = intProp; 
     this.strLabel = strLabel; 
    } 

    public Set<StyleEnum> getComplexSubset() { 
     initSubsets(); 
     return complexSubsets.get(this); 
    } 

    private static void initSubsets() { 
     if (complexSubsets == null) { 
      Map<StyleEnum, Set<StyleEnum>> map = new EnumMap<>(StyleEnum.class); 
      map.put(NONE, Collections.unmodifiableSet(EnumSet.of(
       BOLD, ITALIC))); 
      map.put(BOLD, Collections.unmodifiableSet(EnumSet.of(
       UNDERLINE))); 
      map.put(ITALIC, Collections.unmodifiableSet(EnumSet.of(
       UNDERLINE))); 
      map.put(UNDERLINE, Collections.emptySet()); 
      map.put(STRIKETHROUGH, Collections.unmodifiableSet(EnumSet.of(
       NONE))); 
      map.put(B_AND_I, Collections.unmodifiableSet(EnumSet.of(
       BOLD, ITALIC))); 
      complexSubsets = Collections.unmodifiableMap(map); 

      assert complexSubsets.keySet().containsAll(
       EnumSet.allOf(StyleEnum.class)) : 
       "Not all values have subsets defined"; 
     } 
    } 
} 
+0

bien sûr, je certainement thougt de celui-ci, mais je suis tout à essayer de dire:. En bon OO ma conception a seulement une instance donnée savent exactement ce qu'il se tiendra donc nous allons garder cette connaissance profondément encapsulé à l'intérieur. . –

+0

Une note:. l'astuce de la carte semble (à mon humble avis) « moins élégante » par rapport à l'idée initiale et encore plus que je ne l'aime Map'style parce que toute l'utilité de Enum est censé SHINE utilisé dans EnumSet (cf javadoc et le livre « java efficace » par Joshua Bloch.) Mais le code peut fonctionner comme je voulais, si la carte et le EnumSet intérieur est possible. sauf que la construction de style « l'EnumSet est si horrible et douloureux ... –

+0

Je comprends Votre point de vue personnel, j'ai toujours trouvé des coupli ng données à enum constantes maladroit; Je préfère garder les constantes enum propres et utiliser EnumMaps pour associer des données avec des valeurs enum. Je suis un peu d'accord avec votre point de vue sur la lourdeur de 'EnumSet.of'; une méthode privée comme 'static Set setOf (valeurs StyleEnum ...)' peut rendre les choses un peu plus lisibles. – VGR