क्या अपने स्ट्रिंग प्रतिनिधित्व को सरल बनाने के लिए एनमों के लिए नामांकित सभी-कैप्स के खिलाफ जाना ठीक है?


14

कई बार मैंने देखा है कि लोग शीर्षक-मामले या यहां तक ​​कि सभी निचले-मामले का उपयोग करते हुए एनम स्थिरांक का नामकरण करते हैं, उदाहरण के लिए:

enum Color {
  red,
  yellow,
  green;
}

यह उनके स्ट्रिंग फॉर्म के साथ सरल और आसान काम करता है, यदि आप throw new IllegalStateException("Light should not be " + color + ".")उदाहरण के लिए करना चाहते हैं ।

यदि एनम है तो यह अधिक स्वीकार्य लगता है private, लेकिन मुझे अभी भी यह पसंद नहीं है। मुझे पता है कि मैं स्ट्रिंग क्षेत्र के साथ एक एनम कंस्ट्रक्टर बना सकता हूं, और फिर इस तरह से नाम वापस करने के लिए स्ट्रिंग को ओवरराइड कर सकता हूं:

enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}

लेकिन देखो कितना लंबा है। यदि आप एक छोटी सी दुश्मनी रखते हैं, जिसे आप सरल रखना चाहते हैं, तो ऐसा करना कष्टप्रद है। क्या यहां सिर्फ अपरंपरागत मामले प्रारूपों का उपयोग करना ठीक है?


4
इसका एक सम्मेलन। क्या आपके पास सम्मेलन को तोड़ने का कारण है? यह आप पर निर्भर है।

9
बस सोच रहा था कि अपवाद संदेश के साथ क्या गलत है Light should not be RED.। आखिरकार, यह संदेश डेवलपर के लिए है, उपयोगकर्ता को इसे कभी नहीं देखना चाहिए।
ब्रैंडिन

1
@ ब्रैंडिन यदि रंग कार्यान्वयन विस्तार से अधिक है, तो किसी को भी इसे नहीं देखना चाहिए। बेशक, तब मुझे लगता है कि इस सवाल को छोड़ दिया जाता है कि हमें एक अच्छा स्ट्रांग रूप क्यों चाहिए।
कोडब्रेकर

8
दिन के अंत में यह आपके ऊपर है। अगर मैं आपके कोड को डिबग कर रहा था और एक अपवाद संदेश देखा, तो Light should not be YELLOW.मुझे लगता है कि यह किसी प्रकार का एक निरंतर है, theString () विधि केवल डीबगिंग उद्देश्यों के लिए है, इसलिए मैं नहीं देखता कि आपको यह बदलने की आवश्यकता क्यों है कि यह उस संदेश में कैसा दिखता है।
ब्रैंडिन

1
मुझे लगता है कि उत्तर 'ओके' के आपके विचार पर आधारित है। दुनिया है, सबसे अधिक संभावना है, अगर आप ऐसा करते हैं तो आप आग की लपटों में नहीं जा सकते हैं और आप सफलतापूर्वक एक कार्यक्रम भी लिख सकते हैं। क्या यह उपयोगी है? meh भी व्यक्तिपरक। यदि आपको कुछ लाभ मिलता है, तो क्या यह आपके लिए लायक है और क्या यह दूसरों को प्रभावित करेगा? वे सवाल हैं जिनका मैं ध्यान रखूंगा।
गार्ट क्लैबोर्न

जवाबों:


14

संक्षिप्त उत्तर निश्चित रूप से, क्या आप अनिवार्य रूप से स्थिरांक हैं के लिए नामकरण सम्मेलनों के साथ तोड़ना चाहते हैं ... JLS से उद्धरण :

लगातार नाम

इंटरफ़ेस प्रकारों में स्थिरांक के नाम होने चाहिए, और वर्ग प्रकारों के अंतिम चर पारंपरिक रूप से हो सकते हैं, एक या अधिक शब्दों, शब्दकोष, या संक्षिप्तताओं का क्रम, सभी अपरकेस, अंडरस्कोर "_" वर्णों द्वारा अलग किए गए घटकों के साथ। लगातार नाम वर्णनात्मक होना चाहिए और अनावश्यक रूप से संक्षिप्त नहीं होना चाहिए। परंपरागत रूप से वे भाषण का कोई भी उपयुक्त हिस्सा हो सकते हैं।

लंबे उत्तर, जिनके उपयोग के संबंध में toString(), यह निश्चित रूप से ओवरराइड करने की विधि है यदि आप मूल्यों का अधिक पठनीय प्रतिनिधित्व चाहते enumहैं। Object.toString()(जोर मेरा) से उद्धृत :

वस्तु का एक स्ट्रिंग प्रतिनिधित्व रिटर्न करता है। सामान्य तौर पर, toStringविधि एक स्ट्रिंग लौटाती है जो इस ऑब्जेक्ट को "पाठ का प्रतिनिधित्व करता है" । परिणाम एक संक्षिप्त लेकिन जानकारीपूर्ण प्रतिनिधित्व होना चाहिए जो किसी व्यक्ति के लिए पढ़ना आसान है । यह अनुशंसा की जाती है कि सभी उपवर्ग इस पद्धति को ओवरराइड करें।

अब, मुझे यकीन नहीं है कि कुछ उत्तर मानों के enumsसाथ-साथ-साथ-साथ-साथ में बदलने के बारे में बात करने के लिए क्यों उछले String, लेकिन मैं यहां अपना रूप भी दूंगा। enumमूल्यों के इस तरह के क्रमांकन को name()या तो या ordinal()विधियों का उपयोग करके आसानी से ध्यान रखा जा सकता है । दोनों हैं finalऔर इस प्रकार आप लौटाए गए मूल्यों के बारे में सुनिश्चित हो सकते हैं जब तक कि मूल्यों का नाम या स्थिति नहीं बदलती । मेरे लिए, यह एक स्पष्ट पर्याप्त मार्कर है।

मैं ऊपर से जो इकट्ठा करता हूं वह है: आज, आप YELLOWबस "पीला" के रूप में वर्णन करना चाह सकते हैं । कल, आप इसे "पैनटोन मिनियन येलो" के रूप में वर्णित करना चाह सकते हैं । इन विवरणों को कॉलिंग से लौटाया जाना चाहिए toString(), और मुझे name()या तो ordinal()बदलने की उम्मीद नहीं है । यदि मैं ऐसा करता हूं, तो मुझे अपने कोडबेस या मेरी टीम के भीतर हल करने की आवश्यकता है, और केवल enumनामकरण शैली की तुलना में एक बड़ा सवाल बन जाता है

अंत में, यदि आप सभी करना चाहते हैं, तो अपने मूल्यों का अधिक पठनीय प्रतिनिधित्व करने के लिए enum, मैं अभी भी सम्मेलनों से चिपके रहने और फिर ओवरराइड करने का सुझाव दूंगा toString()। यदि आप भी उन्हें डेटा फ़ाइल में या अन्य गैर-जावा गंतव्यों में क्रमबद्ध करने का इरादा रखते हैं, तो आपके पास अभी भी आपके पास वापस जाने के लिए तरीके name()और ordinal()तरीके हैं, इसलिए ओवरराइडिंग पर झल्लाहट करने की कोई आवश्यकता नहीं है toString()


5

संशोधित न करें ENUMकि सिर्फ बुरा कोड गंध है। मान लें कि एक एनम एक एनम है और एक स्ट्रिंग एक स्ट्रिंग है।

इसके बजाय, स्ट्रिंग मानों के लिए एक CamelCase कनवर्टर का उपयोग करें।

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

कई खुले स्रोत पुस्तकालय हैं जो पहले से ही जावा के लिए इस मुद्दे को हल करते हैं।

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/CaseFormat.html


क्या यह कुछ धार के मामलों में गैर-नियतात्मक नहीं होगा? (एक विशिष्ट कनवर्टर का व्यवहार नहीं है, लेकिन सामान्य सिद्धांत)
पैंजरक्रिस

-1 एक तृतीय-पक्ष लायब्रेरी जोड़ना जो आप मूल स्ट्रिंग स्वरूपण के लिए नहीं चाहते हैं वह ओवरकिल हो सकती है।
user949300

1
@ user949300 कोड को कॉपी करें, अपना या कभी भी लिखें। आप बात याद कर रहे हैं।
रिएक्टगुलर

क्या आप "बिंदु" पर विस्तार से बता सकते हैं? "एक एनम एक एनम और एक स्ट्रिंग एक स्ट्रिंग हो" अच्छा लगता है, लेकिन इसका वास्तव में क्या मतलब है?
user949300

1
एनम प्रकार सुरक्षा प्रदान करता है। वह "पोटेटो" को एक रंग के रूप में पारित नहीं कर सकता। और, शायद, वह एनुम में अन्य डेटा शामिल करता है, जैसे कि थ्रू आरजीबी मूल्य, बस इसे कोड में नहीं दिखाता है। एक स्ट्रिंग के बजाय एक एनम का उपयोग करने के कई अच्छे कारण हैं।
user949300

3

मेरे जावा कोड और एक डेटाबेस या क्लाइंट ऐप के बीच में एनम भेजना, मैं अक्सर स्ट्रिंग्स के रूप में एनम मूल्यों को पढ़ना और लिखना समाप्त करता हूं। toString()स्पष्ट रूप से कहा जाता है जब तारों को समतल करना। कुछ एनमों पर ओवरराइडिंग स्ट्रीडिंग () का मतलब था कि कभी-कभी मैं बस

"<input type='checkbox' value='" + MY_CONST1 + "'>"

और कभी-कभी मुझे कॉल करने के लिए याद करना पड़ता था

"<input type='checkbox' value='" + MY_CONST1.name() + "'>"

जिसके कारण त्रुटियां हुईं, इसलिए मैं अब ऐसा नहीं करता। वास्तव में, मैं Enum पर किसी भी तरीके को ओवरराइड नहीं करता हूं क्योंकि यदि आप उन्हें पर्याप्त क्लाइंट कोड में फेंकते हैं, तो आप अंततः किसी की उम्मीदों को तोड़ देंगे।

की तरह अपने खुद के नई विधि नाम है, public String text()या toEnglish()या जो कुछ भी।

यहाँ एक छोटी सहायक क्रिया है जो आपको कुछ टाइपिंग बचा सकती है यदि आपके पास ऊपर की तरह बहुत सारी दुश्मनी है:

public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}

हमेशा .toUpperCase () या .toLowerCase () कॉल करना आसान होता है, लेकिन मिश्रित-केस वापस लेना मुश्किल हो सकता है। रंग पर विचार करें, "ब्लु डी फ्रांस।" फ्रांस को हमेशा पूंजीकृत किया जाता है, इसलिए यदि आप उस में भाग लेते हैं, तो आप अपने एनुम में एक टेक्स्ट लॉवर () विधि जोड़ना चाहते हैं। जब आप एक वाक्य की शुरुआत में, बनाम एक वाक्य के बीच में, बनाम एक शीर्षक में इस पाठ का उपयोग करते हैं, तो आप देख सकते हैं कि एक एकल toString()विधि कैसे कम होने वाली है। और यह कि जावा पहचानकर्ताओं में अवैध वर्णों को भी नहीं छूता है, या जो टाइप करने के लिए एक दर्द है क्योंकि वे मानक कीबोर्ड, या उन वर्णों पर प्रतिनिधित्व नहीं करते हैं जिनके पास मामला नहीं है (कांजी, आदि)।

enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}

इनको सही तरीके से इस्तेमाल करना इतना मुश्किल नहीं है:

IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")

उम्मीद है कि यह भी प्रदर्शित करता है कि मिश्रित-मामले एनम मूल्यों का उपयोग करने से आपको भी निराशा होगी। अंडरस्कोर एनम स्थिरांक के साथ ऑल-कैप रखने का एक अंतिम कारण यह है कि ऐसा करने से प्रिंसिपल ऑफ लेस्ट एस्टनमेंट का अनुसरण होता है। लोग इसकी उम्मीद करते हैं, इसलिए यदि आप कुछ अलग करते हैं, तो आपको हमेशा खुद को समझाते रहना होगा, या अपने कोड का दुरुपयोग करने वाले लोगों से निपटना होगा।


3
toString()एक एनम पर ओवरराइड करने का सुझाव मेरे लिए कोई मायने नहीं रखता है। यदि आप enum नामों की गारंटीकृत डिफ़ॉल्ट व्यवहार चाहते हैं, तो उपयोग करें name()। मुझे यह "लुभाने" के toString()लिए सही कुंजी प्रदान करने के लिए भरोसा करने के लिए बिल्कुल भी नहीं मिला valueOf(String)। मुझे लगता है कि यदि आप अपने दुश्मनों को बेवकूफ बनाना चाहते हैं, तो यह एक बात है, लेकिन मुझे नहीं लगता कि यह एक अच्छा पर्याप्त कारण है कि आपको कभी भी ओवरराइड नहीं करना चाहिए toString()
कोडब्रेकर

1
इसके अलावा, मुझे यह मिला, जो अनुशंसा करता है (जैसा कि मुझे विश्वास था कि) का नेतृत्व किया गया था कि एनमों पर ओवरराइड करना वास्तव में एक अच्छी बात है: stackoverflow.com/questions/13291076/…
कोडब्रेकर

@codebreaker toString () को संक्षेप में कहा जाता है जब तार को समतल करना। कुछ एनमों पर ओवरराइडिंग स्ट्रीडिंग () का मतलब था कि कभी-कभी मैं बस कर सकता <input type='checkbox' value=" + MY_CONST1 + ">था, और कभी-कभी मुझे कॉल करने के लिए याद रखना पड़ता था <input type='checkbox' value=" + MY_CONST1.name() + ">, जिसके कारण त्रुटियां होती थीं।
ग्लेनपेटर्सन

ठीक है, यह एक अच्छा बिंदु है, लेकिन यह वास्तव में केवल तब मायने रखता है जब आप उनके नाम के साथ "सीरमाइज़िंग" करते हैं (जो कि मेरे उदाहरण के बारे में चिंता करने की आवश्यकता नहीं है)।
कोडब्रेकर

0

यदि थोड़ी सी भी संभावना है कि ये स्ट्रिंग प्रतिनिधित्व डेटाबेस या पाठ फ़ाइलों जैसे स्थानों में संग्रहीत किए जा सकते हैं, तो उन्हें वास्तविक एनम स्थिरांक से बंधे होने पर अत्यधिक समस्याग्रस्त हो जाएगा यदि आपको कभी भी अपनी एनम को फिर से भरने की आवश्यकता होती है।

क्या होगा अगर एक दिन आप नाम बदलने Color.Whiteका निर्णय लेते Color.TitaniumWhiteहैं जबकि "व्हाइट" युक्त डेटा फाइलें हैं?

इसके अलावा, एक बार जब आप एनम कॉन्स्टेंट को स्ट्रिंग्स में परिवर्तित करना शुरू कर देते हैं, तो अगला कदम सड़क के नीचे उपयोगकर्ता को देखने के लिए स्ट्रिंग्स उत्पन्न करना होगा, और यहाँ समस्या यह है, जैसा कि मुझे यकीन है कि आप पहले से ही जानते हैं, कि जावा का वाक्यविन्यास नहीं है पहचानकर्ताओं के भीतर रिक्त स्थान की अनुमति दें। (आपके पास कभी नहीं होगा Color.Titanium White।) इसलिए, चूंकि आपको उपयोगकर्ता को दिखाने के लिए एनम नाम उत्पन्न करने के लिए संभवतः एक उचित तंत्र की आवश्यकता होगी, इसलिए अनावश्यक रूप से अपने एनम को उलझाने से बचना सबसे अच्छा है।

कहा जा रहा है कि, आप निश्चित रूप से आगे बढ़ सकते हैं और वही कर सकते हैं जो आप करने की सोच रहे हैं, और फिर बाद में अपनी एनम को फिर से रिफेंक्टर करें, जब कंस्ट्रक्टर को नाम दिया जाए, तब (और अगर) आप परेशानी में हैं।

आप nameफ़ील्ड की घोषणा करके public finalऔर गेटर को खो कर अपने एनम-विथ-कंस्ट्रक्टर को बंद कर सकते हैं । (यह प्यार क्या है कि जावा प्रोग्रामर गेटर्स के प्रति है?)


एक सार्वजनिक अंतिम स्थैतिक को कोड में संकलित किया जाता है जो इसे उस वर्ग के संदर्भ के बजाय वास्तविक स्थिरांक के रूप में उपयोग करता है जो इससे आता है। कोड की आंशिक पुनर्संरचना (या जार की जगह) करते समय यह कई अन्य मजेदार त्रुटियों का कारण बन सकता है। यदि आप सुझाव दे रहे हैं public final static int white = 1;या public final static String white = "white";(फिर से सम्मेलन को तोड़ने से अलग), तो यह उस प्रकार की सुरक्षा खो देता है जो कि एनम प्रदान करता है।

@MichaelT Enum क्षेत्र स्थिर नहीं हैं। एक उदाहरण प्रत्येक एनम स्थिर के लिए बनाया गया है, और एनम के सदस्य उस उदाहरण के सदस्य चर हैं। एक public finalइंस्टेंस फील्ड जो कंस्ट्रक्टर से इनिशियलाइज़ हो जाता है, बिल्कुल नॉन-फ़ाइनल फ़ील्ड की तरह व्यवहार करता है, सिवाय इसके कि आपको इसे संकलित करने के लिए संकलन-समय पर रोका जाता है। आप इसे प्रतिबिंब के माध्यम से संशोधित कर सकते हैं और इसके लिए संदर्भित सभी कोड तुरंत नए मूल्य को देखना शुरू कर देंगे।
माइक नाकिस

0

तर्क के अनुसार, नामकरण अधिवेशन नामकरण DRY का उल्लंघन करता है । (और YAGNI )। उदाहरण के लिए, आपके कोड उदाहरण में # 2: "RED" और "रेड" दोहराए जाते हैं।

तो, क्या आप आधिकारिक सम्मेलन का पालन करते हैं या DRY का पालन करते हैं? तुम्हारा कॉल।

अपने कोड में, मैं DRY का पालन करूंगा। हालांकि, मैं Enum वर्ग पर एक टिप्पणी में कहूंगा, "सभी अपरकेस नहीं क्योंकि (यहां स्पष्टीकरण)"

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.