जावा डेवलपर्स कुछ एपीआई डिजाइन करने के रूप में, हम अक्सर इस मुद्दे पर आते हैं। मैं अपने ही संदेह reconfirming रहा था जब मैं इस पोस्ट भर में आया था, लेकिन मैं यह करने के लिए एक वर्बोज़ वैकल्पिक हल है:
// class name is awful for this example, but it will make more sense if you
// read further
public interface MetaDataKey<T extends Serializable> extends Serializable
{
T getValue();
}
public final class TypeSafeKeys
{
static enum StringKeys implements MetaDataKey<String>
{
A1("key1");
private final String value;
StringKeys(String value) { this.value = value; }
@Override
public String getValue() { return value; }
}
static enum IntegerKeys implements MetaDataKey<Integer>
{
A2(0);
private final Integer value;
IntegerKeys (Integer value) { this.value = value; }
@Override
public Integer getValue() { return value; }
}
public static final MetaDataKey<String> A1 = StringKeys.A1;
public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}
उस बिंदु पर, आप वास्तव में एक निरंतर enum
eration मूल्य जा रहा है का लाभ प्राप्त करता है (और के सभी भत्ते जो उसके साथ जाते हैं), साथ ही interface
का अनूठा कार्यान्वयन भी है, लेकिन आपके पास enum
द्वारा वैश्विक पहुंच योग्यता है।
स्पष्ट रूप से, यह शब्दशः जोड़ता है, जो कॉपी/पेस्ट गलतियों की संभावना बनाता है। आप enum
s public
बना सकते हैं और बस उनकी पहुंच में एक अतिरिक्त परत जोड़ सकते हैं।
डिजाइन कि इन सुविधाओं का इस्तेमाल करते हैं क्योंकि वे आम तौर इस तरह के एक नाम है, जो अनजाने एक समान है, फिर भी अलग उद्देश्य के लिए codebase भर में दोहराया जा सकता है, कुछ अन्य अनूठा मूल्य के साथ मिलकर कर रहे हैं भंगुर equals
कार्यान्वयन से ग्रस्त हो जाते हैं। बोर्ड में enum
एस का उपयोग करके, समानता एक फ्रीबी है जो इस तरह के भंगुर व्यवहार से प्रतिरक्षा है।
शब्दावली से परे प्रणाली जैसे प्रमुख दोष, वैश्विक स्तर पर अद्वितीय कुंजी (उदाहरण के लिए, जेएसओएन से मार्शलिंग) के बीच आगे और पीछे परिवर्तित करने का विचार है। यदि वे केवल चाबियाँ हैं, तो उन्हें स्मृति को बर्बाद करने की लागत पर सुरक्षित रूप से पुनर्स्थापित (डुप्लिकेट) किया जा सकता है, लेकिन पहले की कमजोरी का उपयोग करके - equals
- एक लाभ है।
एक समाधान यह है कि वैश्विक उदाहरण प्रति एक गुमनाम प्रकार के साथ यह अव्यवस्थित द्वारा वैश्विक कार्यान्वयन विशिष्टता प्रदान करता है:
public abstract class BasicMetaDataKey<T extends Serializable>
implements MetaDataKey<T>
{
private final T value;
public BasicMetaDataKey(T value)
{
this.value = value;
}
@Override
public T getValue()
{
return value;
}
// @Override equals
// @Override hashCode
}
public final class TypeSafeKeys
{
public static final MetaDataKey<String> A1 =
new BasicMetaDataKey<String>("value") {};
public static final MetaDataKey<Integer> A2 =
new BasicMetaDataKey<Integer>(0) {};
}
ध्यान दें कि प्रत्येक उदाहरण के एक गुमनाम कार्यान्वयन का उपयोग करता है, लेकिन कुछ नहीं इसे लागू करने की जरूरत है , इसलिए {}
खाली हैं। यह भ्रमित और परेशान दोनों है, लेकिन यह काम करता है अगर इंस्टेंस संदर्भ बेहतर हैं और अव्यवस्था को कम से कम रखा जाता है, हालांकि यह कम अनुभवी जावा डेवलपर्स के लिए थोड़ा सा गूढ़ हो सकता है, जिससे इसे बनाए रखना मुश्किल हो जाता है।
अंत में, वैश्विक विशिष्टता और पुन: असाइनमेंट प्रदान करने का एकमात्र तरीका यह हो रहा है कि क्या हो रहा है के साथ थोड़ा और रचनात्मक होना है।कि मैंने देखा है विश्व स्तर पर साझा इंटरफेस के लिए सबसे आम उपयोग मेटाडाटा बाल्टी कि विभिन्न प्रकार के साथ, विभिन्न मूल्यों का एक बहुत मिश्रण के लिए करते हैं के लिए कर रहे हैं (T
, कुंजी आधार प्रति एक पर):
public interface MetaDataKey<T extends Serializable> extends Serializable
{
Class<T> getType();
String getName();
}
public final class TypeSafeKeys
{
public static enum StringKeys implements MetaDataKey<String>
{
A1;
@Override
public Class<String> getType() { return String.class; }
@Override
public String getName()
{
return getDeclaringClass().getName() + "." + name();
}
}
public static enum IntegerKeys implements MetaDataKey<Integer>
{
A2;
@Override
public Class<Integer> getType() { return Integer.class; }
@Override
public String getName()
{
return getDeclaringClass().getName() + "." + name();
}
}
public static final MetaDataKey<String> A1 = StringKeys.A1;
public static final MetaDataKey<Integer> A2 = IntegerKeys.A2;
}
यह प्रदान करता है पहले विकल्प के रूप में एक ही लचीलापन, और यह प्रतिबिंब के माध्यम से संदर्भ प्राप्त करने के लिए एक तंत्र प्रदान करता है, यदि यह बाद में आवश्यक हो जाता है, इसलिए बाद में तत्काल आवश्यकता की आवश्यकता से बचें। यह कई त्रुटि प्रवण प्रतिलिपि/पेस्ट गलतियों से भी बचाता है जो पहला विकल्प प्रदान करता है क्योंकि पहली विधि गलत होने पर यह संकलित नहीं होगी, और दूसरी विधि को बदलने की आवश्यकता नहीं है। एकमात्र नोट यह है कि आपको यह सुनिश्चित करना चाहिए कि enum
एस का उपयोग उस फैशन में किया जाना चाहिए public
किसी को भी त्रुटियों तक पहुंचने से बचने के लिए क्योंकि उन्हें आंतरिक enum
तक पहुंच नहीं है; यदि आप उन MetaDataKey
को एक मार्शल तार में नहीं जा रहे हैं, तो उन्हें बाहरी पैकेजों से छिपाने के लिए इस्तेमाल किया जा सकता है, उन्हें स्वचालित रूप से त्यागने के लिए उपयोग किया जा सकता है (मार्शलिंग के दौरान, यह देखने के लिए प्रतिबिंबित रूप से जांचें कि enum
पहुंच योग्य है या नहीं, और यदि ऐसा नहीं है, फिर कुंजी/मान को अनदेखा करें)। यदि संदर्भों को बनाए रखा जाता है (उदाहरण के लिए enum
उदाहरण वैसे भी हैं) उदाहरण के लिए दो तरीकों को छोड़कर public
बनाकर प्राप्त या खो गया कुछ भी नहीं है।
मैं चाहता हूं कि उन्होंने इसे बनाया ताकि enum
एस जावा में ऑब्जेक्ट्स का विस्तार कर सके। शायद जावा 9 में?
अंतिम विकल्प वास्तव में आपकी आवश्यकता को हल नहीं करता है, क्योंकि आप मूल्यों के लिए पूछ रहे थे, लेकिन मुझे संदेह है कि यह वास्तविक लक्ष्य की ओर जाता है।
यह दृष्टिकोण मेरी समस्या का समाधान नहीं करता है जब तक कि मैं 'enum B implemts ए
यही वह बिंदु है जिसे मैं बनाने की कोशिश कर रहा हूं - आपकी समस्या को एकल 'एनम' का उपयोग करके हल नहीं किया जा सकता है। – Jorn
अब कम से कम मैं समझता हूं कि 'enum' मेरी आवश्यकता के लिए इतना उपयुक्त नहीं है। धन्यवाद! –