2013-01-18 57 views
5

我創建了一個Enum來定義某些操作。針對外部API編程我不得不使用Integer來表示此操作。這就是爲什麼我向Enum添加了一個整型實例字段。這應該與Joshua Bloch的Effective Java一致,而不是依賴於ordinal()或使用values()[index]的Enum常量的順序。從一個唯一的實例值中創建一個枚舉工廠方法

public enum Action { 

    START(0), 

    QUIT(1); 

    public final int code; 

    Protocol(int code) { 
     this.code = code; 
    } 
} 

我從API整數值what,現在我想創建一個枚舉值了吧,我怎麼能在最通用的方式實現這一點?

很明顯,添加這樣的工廠方法是行不通的。你不能實例化一個Enum。

Action valueOf(int what) { 
    return new Action(what); 
} 

當然,我總是可以做一個switch-case語句並添加所有可能的代碼並返回相應的常量。但我想避免在兩個地方同時定義它們。

回答

5

如果你將有很多人,你可以使用一個HashMap<Integer, Action>

private static final Map<Integer, Action> actions = new HashMap<>(values().size, 1); 

static { 
    for (Action action : values()) 
     actions.put(action.code, action); 
} 

// ... 

public static Action valueOf(int what) { 
    return actions.get(what); 
} 

這是如果你將有大量Action值,因爲HashMap查找有用O(1)。

+0

你可以使用正確的大小來初始化地圖:'new HashMap <>(Action.values()。length,1);'(如果沒有多少值但不會產生影響任何做它)。 – assylias

+0

@assylias有趣的是,我查看了源代碼,構造函數實際上忽略了加載因子:*請注意,此實現忽略loadFactor;它始終使用3/4的加載因子。這簡化了代碼,並且通常會提高性能。* –

+0

我不知道 - 有趣。 – assylias

1

如果你確信你的代碼將永遠是連續的,從0開始的話,最有效的辦法是

public enum Action { 
    START(0), 

    QUIT(1); 

    public static final Action[] ACTIONS; 
    static { 
     ACTIONS = new Action[values().length]; 
     for(Action a : values()) { 
     ACTIONS[a.code] = a; 
     } 
    } 

    public final int code; 

    Protocol(int code) { 
     this.code = code; 
    } 
} 
0

我會親自把它簡單(YAGNI),並使用序號值

  • 我會保持邏輯的枚舉內,以確保外部的代碼不知道是實現細節,不依賴於它
  • 我WOU ld確保我有一個測試失敗,如果有事情中斷(即如果更改QUIT(1)QUIT(2)例如

    public enum Action { 
    
        START(0), 
        QUIT(1); 
        private final int code; 
    
        Action(int code) { 
         this.code = code; 
        } 
    
        public int getCode() { 
         return code; 
        } 
    
        public static Action of(int code) { 
         try { 
          return Action.values()[code]; 
         } catch (IndexOutOfBoundsException e) { 
          throw new IllegalArgumentException("not a valid code: " + code); 
         } 
        } 
    } 
    

    測試

    @Test 
    public testActionEnumOrder() { 
        int i = 0; 
        for (Action a : Action.values()) { 
         assertEquals(a.getCode(), i++); 
        } 
    } 
    

    :如果數字不從0開始或沒有增量)

枚舉代碼,測試將失敗。發生這種情況時,可以使用HashMap或查找循環。

+0

有趣。我不會贊成使用那些在代碼更改的情況下更可能中斷的代碼,但這不是真的。但我沒有考慮選擇前者,並用測試案例進行備份。 –

+0

@MaxRhan如果擔心測試可能無法運行,您甚至可以將該檢查包含在靜態初始化程序塊中,以便每次加載該類時運行它。任何破壞設計的東西都會很快被發現。 – assylias

相關問題