2013-01-18 18 views
5

से एक enum फैक्ट्री विधि बनाएं मैंने कुछ क्रियाओं को परिभाषित करने के लिए एक Enum बनाया है। बाहरी एपीआई के खिलाफ प्रोग्रामिंग मुझे इस क्रिया को व्यक्त करने के लिए Integer का उपयोग करने के लिए मजबूर होना पड़ता है। यही कारण है कि मैंने अपने एनम में एक पूर्णांक उदाहरण फ़ील्ड जोड़ा है। यह ordinal() पर निर्भर होने के बजाय या values()[index] का उपयोग करके एनम स्थिरांक के आदेश के बजाय, जोशुआ ब्लोच के प्रभावी जावा के साथ समझौता किया जाना चाहिए।एक अद्वितीय उदाहरण मान

public enum Action { 

    START(0), 

    QUIT(1); 

    public final int code; 

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

मैं एपीआई से एक पूर्णांक मूल्य what हो और अब मैं इसे से बाहर एक Enum मूल्य बनाना चाहते हैं, कैसे मैं सबसे सामान्य फैशन में यह लागू कर सकते हैं?

जाहिर है, ऐसी फैक्ट्री विधि जोड़कर काम नहीं करेगा। आप एक एनम को तत्काल नहीं कर सकते हैं।

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

बेशक, मैं हमेशा एक स्विच-केस स्टेटमेंट बना सकता हूं और सभी संभावित कोड जोड़ सकता हूं और उचित स्थिरता वापस कर सकता हूं। लेकिन मैं उन्हें एक ही समय में दो स्थानों पर परिभाषित करना चाहता हूं।

उत्तर

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); 
} 

यह उपयोगी आप के बाद से HashMap देखने है Action मूल्यों की एक बड़ी संख्या के लिए जा रहे हैं है हे (1)।

+0

आप सही आकार के साथ मानचित्र को प्रारंभ कर सकते हैं: 'नया हैश मैप <> (एक्शन.वैल्यूज() लम्बाई, 1);' (यदि कोई मूल्य नहीं है तो इससे कोई फर्क नहीं पड़ता है लेकिन इसकी कीमत नहीं है कुछ भी कर रहा है)। – assylias

+0

@assylias मजेदार, मैंने स्रोत कोड में देखा है और निर्माता वास्तव में लोड कारक को अनदेखा करता है: * ध्यान दें कि यह कार्यान्वयन लोड फैक्टर को अनदेखा करता है; यह हमेशा 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) रखेंगे कर रहे हैं और क्रमसूचक मान का उपयोग लेकिन :

  • मैं enum भीतर तर्क रखें कि कार्यान्वयन विस्तार के बारे में पता नहीं है यकीन है कि बाहर कोड बनाने के लिए होगा और यह पर निर्भर नहीं करता
  • मैं wou एलडी सुनिश्चित करें कि मेरे पास एक परीक्षण है जो कुछ तोड़ने में विफल रहता है (यानी। संख्या 0 से शुरू करता है, तो नहीं है या वृद्धिशील नहीं हैं)

enum कोड:

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++); 
    } 
} 

आप उदाहरण के लिए QUIT(2) करने के लिए QUIT(1) को बदलते हैं परीक्षण विफल हो जाएगा। जब ऐसा होता है, तो आप हैश मैप या लुकअप लूप का उपयोग कर सकते हैं।

+0

दिलचस्प। मैं उस कोड का उपयोग करने का पक्ष नहीं लेगा जो कोड पर परिवर्तनों के कारण तोड़ने की अधिक संभावना है जहां यह सत्य नहीं है। लेकिन मैंने पूर्व को चुनने और टेस्ट केस के साथ इसका समर्थन करने में विचार नहीं किया है। –

+0

@MaxRhan यदि आपको डर है कि परीक्षण नहीं चलाया जा सकता है, तो आप एक स्थिर प्रारंभिक ब्लॉक में चेक भी शामिल कर सकते हैं ताकि कक्षा हर बार लोड होने पर इसे चलाया जा सके। डिजाइन को तोड़ने वाली कुछ भी जल्द ही देखी जाएगी। – assylias