2017-04-11 79 views
1

我正在處理一些關於我使用某些不安全(無類型安全)的地方的一些工作,該模型的部分字符串或int表示。 並利用Enum和EnumSet最佳實踐。EnumSet <E>的最佳初始化E

一個特別的困難是這個用例:一個Enum,其中每個實例都擁有自己姐妹的[0..n]的EnumSet。

要剝離它的基本要點,我基於我的問題在Joshua Bloch StyleEnum。因此,我們得到了BOLD,ITALIC,UNDERLINE,STRIKETHROUGH的枚舉。讓我們想象一個B_AND_I,它將擁有{BOLD,ITALIC}。

請不要忽略這個毫無意義的例子:在真實系統中,這個子集是建立在啓動時加載的一些變化規則的基礎上的。

的目標是,一旦這種計算已經發生了,沒有什麼可以改變例如特定子EnumSet範圍。 所以我帶着這樣的:

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(){} 

} 

正如你可以看到什麼是真正的愉快或至少優雅在這裏。

在我的夢想:

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瞧!

取而代之的是,我所能做的,似乎扯遠了最終場上

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

然後在theClass描述靜態初始化塊迴路上與(虛擬)標記(NONE)實例介紹了只爲這種(愚蠢的)目的:

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

只有經過計算和儲存子EnumSet。

所以這一切的痛苦,-mostly-,只是因爲一個不能說「新的EnumSet();」 ? 必須有更好的方法嗎?你能指點我的好方向嗎?

+0

不應該'e.complexComputedSubSet = EnumSet.copyOf(someComputedCollection);'就足夠了?你仍然需要刪除'final'關鍵字,但這不應該傷害。 – Thomas

+0

順便說一句,我認爲'EnumSet.noneOf(StyleEnum.class)'應該是等同於'新EnumSet (); 「你在追求。 JavaDoc聲明:「用指定的元素類型創建一個空的枚舉集。」 - 該方法的名字很不幸,雖然:) – Thomas

+0

那是我第一次真正的attemps一個: '私人EnumSet complexComputedSubSet = EnumSet.noneOf(StyleEnum.class);' \t 但這個可愛的線在這可怕的跟蹤解析: \t **'所致:java.lang.ClassCastException:類entity.StyleEnum不是enum' ** '在java.util.EnumSet.noneOf(EnumSet.java:112)'' 在entity.StyleEnum。 (StyleEnum.java:22)'' 在entity.StyleEnum。 (StyleEnum。java:5)' \t 所以我剛剛退出它的使用。 –

回答

0

我將放棄保持輔助坐落在一個實例字段,而是實現它作爲一個靜態的地圖:

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

當然,我肯定對這一點感興趣,但我只是想說:在好的OO中,我的設計說只有一個給定的實例確切地知道它將持有的是什麼,所以讓我們把這些知識深深地封裝在裏面 –

+0

注意:與最初的想法相比,Map技巧似乎(IMHO)'不太優雅',甚至更多我不喜歡Map'style,因爲Enum的所有有用性都應該在EnumSet中使用(cf javadoc和Joshua Bloch的'有效的java'一書)。但是代碼可以按照我的意圖工作,所以Map和內部EnumSet都是可能的,除了EnumSet的風格構造如此令人難以置信和痛苦的... –

+0

我明白了你的觀點。我個人總是發現coupli使數據難以枚舉常量;我更喜歡保持枚舉常量乾淨,並使用EnumMaps將數據與枚舉值相關聯。我有點贊同你關於'EnumSet.of'繁瑣的觀點;像'靜態設置 setOf(StyleEnum values ...)'這樣的私有方法可以使事情變得更加可讀。 – VGR