क्या जावा के संग्रह इंटरफ़ेस का उपयोग करने का एक अच्छा कारण है?


11

मैंने यह तर्क सुना है कि आपको उपलब्ध सबसे सामान्य इंटरफ़ेस का उपयोग करना चाहिए ताकि आप उस इंटरफ़ेस के किसी विशेष कार्यान्वयन से बंधे न हों। क्या यह तर्क java.util.Collection जैसे इंटरफेस पर लागू होता है ?

मैं बहुत कुछ देखना चाहूंगा जैसे कि निम्नलिखित:

List<Foo> getFoos()

या

Set<Foo> getFoos()

के बजाय

Collection<Foo> getFoos()

आखिरी स्थिति में, मुझे नहीं पता कि मैं किस तरह के डेटा सेट के साथ काम कर रहा हूं, जबकि पहले दो उदाहरणों में मैं ऑर्डर देने और विशिष्टता के बारे में कुछ अनुमान लगा सकता हूं। क्या java.util.Collection में सेट और सूचियों दोनों के लिए तार्किक माता-पिता होने के बाहर एक उपयोगिता है?

यदि आप एक कोड की समीक्षा करते समय उस नियोजित संग्रह में आए थे , तो आप यह कैसे निर्धारित करेंगे कि क्या इसका उपयोग उचित है, और अधिक विशिष्ट इंटरफ़ेस के साथ इसके प्रतिस्थापन के लिए आप क्या सुझाव देंगे?


3
क्या आपने java.security.cert में देखा कि एक वापसी प्रकार क्या है Collection<List<?>>? कोडिंग हॉरर के बारे में बात करो!
मैकनील

1
@Macneil मुझे नहीं पता कि आप किस वर्ग का जिक्र कर रहे हैं, लेकिन इस तरह का रिटर्न टाइप वास्तव में काफी समझदार हो सकता है। यह अनिवार्य रूप आपको बताता है कि एक है कि संग्रह (यानी एक है कि चीजों में से गुच्छा युक्त नहीं है की एक समझदार आदेश) सूचियों (यानी चीजें हैं जो युक्त है की एक समझदार आदेश) वस्तुओं (यानी आइटम जिसका प्रकार हम के लिए स्थिर नहीं जानते जो भी कारण)। मुझे अनुचित नहीं लगता।
शून्य 3

जवाबों:


13

सार कार्यान्वयन से अधिक समय तक रहते हैं

सामान्य रूप से अधिक सार आपके डिजाइन अब उपयोगी रहने की संभावना है। इसलिए, चूंकि संग्रह अधिक अमूर्त है, इसलिए यह उप-इंटरफेस है तो संग्रह के आधार पर एपीआई डिजाइन संग्रह पर आधारित एक से अधिक उपयोगी रहने की संभावना है।

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

जेनेरिक इंटरफ़ेस डिज़ाइन पर एक नोट

चूंकि आप जेनरिक के साथ संग्रह इंटरफ़ेस का उपयोग करने में रुचि रखते हैं, इसलिए आप निम्नलिखित सहायक हो सकते हैं। जोशुआ बलोच द्वारा प्रभावी जावा एक दृष्टिकोण डिजाइन करते समय निम्नलिखित दृष्टिकोण की सिफारिश करता है जो जेनरिक पर निर्भर करेगा: निर्माता विस्तार, उपभोक्ता सुपर

इसे PECS नियम के रूप में भी जाना जाता है । अनिवार्य रूप से, अगर डेटा उत्पन्न करने वाले सामान्य संग्रह आपकी कक्षा को पास किए जाते हैं, तो हस्ताक्षर इस तरह दिखना चाहिए:

public void pushAll(Collection<? extends E> producerCollection) {}

इस प्रकार इनपुट प्रकार E या E का कोई भी उपवर्ग हो सकता है (E को जावा भाषा में स्वयं का एक सुपर और सब-क्लास दोनों के रूप में परिभाषित किया गया है)।

इसके विपरीत, डेटा का उपभोग करने के लिए पारित किया जाने वाला एक सामान्य संग्रह इस तरह से एक हस्ताक्षर होना चाहिए:

public void popAll(Collection<? super E> consumerCollection) {}

विधि सही ढंग से ई कुल मिलाकर के किसी भी सुपर क्लास के साथ सौदा होगा, इस दृष्टिकोण का उपयोग कर अपने इंटरफेस कम अपने उपयोगकर्ताओं के लिए आश्चर्य की बात कर देगा, क्योंकि आप में पारित करने के लिए सक्षम हो जाएगा Collection<Number>और Collection<Integer>और उन्हें सही ढंग से इलाज किया है।


6

Collectionइंटरफेस है, और सबसे अनुमोदक प्रपत्र Collection<?>, के लिए अच्छा है पैरामीटर है कि आप स्वीकार करते हैं। जावा लाइब्रेरी में उपयोग के आधार पर यह एक रिटर्न प्रकार की तुलना में पैरामीटर प्रकार के रूप में अधिक सामान्य है।

रिटर्न प्रकारों के लिए, मुझे लगता है कि आपकी बात वैध है: यदि लोगों से इसका उपयोग करने की उम्मीद की जाती है, तो उन्हें प्रदर्शन किए जाने वाले ऑपरेशन के आदेश (बिग-ओ अर्थ में) को जानना चाहिए। मैं एक Collectionलौटे पर पुनरावृति करूंगा और इसे दूसरे संग्रह में जोड़ दूंगा , लेकिन यह उस containsपर कॉल करने के लिए थोड़ा पागल प्रतीत होगा , यह नहीं जानते हुए कि क्या यह ओ (1), ओ (लॉग एन), या ओ (एन) ऑपरेशन है। बेशक, सिर्फ इसलिए कि आपके पास Setइसका मतलब यह नहीं है कि यह एक हैशसेट या सॉर्ट किया गया सेट है, लेकिन कुछ बिंदु पर आप यह अनुमान लगाएंगे कि इंटरफ़ेस यथोचित रूप से कार्यान्वित किया गया है (और तब आपको अपनी धारणा के अनुसार प्लान बी में जाने की आवश्यकता होगी। गलत दिखाया गया है)।

जैसा कि टॉम उल्लेख करते हैं, कभी-कभी आपको Collectionएन्कैप्सुलेशन बनाए रखने के लिए ए में वापस जाने की आवश्यकता होती है : आप कार्यान्वयन विवरण को लीक नहीं करना चाहते हैं, भले ही आप कुछ और विशिष्ट वापस कर सकें। या, जिस मामले में टॉम ने उल्लेख किया है, आप अधिक विशिष्ट कंटेनर वापस कर सकते हैं, लेकिन फिर आपको इसका निर्माण करना होगा।


2
मुझे लगता है कि दूसरा बिंदु थोड़ा कमजोर है। आप यह नहीं जानते कि संग्रह कैसा है, चाहे वह संग्रह या सूची का प्रदर्शन करने वाला हो - क्योंकि वे केवल अमूर्त हैं। जब तक आपके पास एक ठोस अंतिम वर्ग न हो, आप वास्तव में नहीं बता सकते।
मार्क एच

इसके अलावा, यदि आप जानते हैं कि कुछ एक संग्रह है, तो आपको पता नहीं है कि इसमें डुप्लिकेट हो सकते हैं या नहीं। उस मोड़ को मोड़ते हुए, एक बार जब संग्रह वापस करना उचित हो सकता है यदि आपके पास एक संग्रह है जिसमें डुप्लिकेट नहीं है और कोई महत्वपूर्ण आदेश नहीं है (जो स्वाभाविक रूप से एक सेट होगा), लेकिन जहां कुछ अच्छे कारण के लिए, वापसी पद्धति का कार्यान्वयन एक सूची का उपयोग करता है। आप किसी सूची को वापस नहीं करना चाहेंगे, क्योंकि इससे महत्वपूर्ण आदेश निकलता है, लेकिन आप एक बनाने के रिग्मारोल से गुजरे बिना एक सेट नहीं लौटा सकते। इसलिए आप एक संग्रह लौटाते हैं।
टॉम एंडरसन

@Tom: अच्छी बात है!
मैकनील

5

मैं इसे पूरे विपरीत दृष्टिकोण से देखूंगा, और पूछूंगा:

यदि आप कोड की समीक्षा करने वाले कोड <> कोड में आए थे, तो आप यह कैसे निर्धारित करेंगे कि क्या इसका उपयोग उचित है?

इसे सही ठहराना काफी आसान है। आप सूची का उपयोग करते हैं जब आपको कुछ कार्यक्षमता की आवश्यकता होती है जो संग्रह द्वारा प्रस्तुत नहीं की जाती है। अगर आपको उस अतिरिक्त कार्यक्षमता की आवश्यकता नहीं है - आपके पास क्या औचित्य है? (और मैं नहीं खरीदूंगा, "मैं इसे देखना पसंद करूंगा")

ऐसे बहुत से मामले हैं जहां आप केवल-पढ़ने के लिए एक संग्रह का उपयोग कर रहे होंगे, एक ही बार में इसे पॉप्युलेट करना, इसके माध्यम से पूरी तरह से पुनरावृत्ति करना - क्या आपको कभी भी चीज़ को मैन्युअल रूप से अनुक्रमित करने की आवश्यकता है?

एक वास्तविक उदाहरण देने के लिए। कहते हैं कि मैं एक डेटाबेस पर एक सरल क्वेरी करता हूं। ( SELECT id,name,rep FROM people WHERE name LIKE '%squared') मैं संबंधित डेटा वापस लेता हूं, व्यक्तिगत वस्तुओं को पॉप्युलेट करता हूं और उन्हें एक व्यक्तिवादी में डाल देता हूं)

  • क्या मुझे सूचकांक द्वारा पहुंचने की आवश्यकता है? - व्यर्थ होगा। इंडेक्स और आईडी के बीच कोई मैपिंग नहीं है।
  • क्या मुझे एक सूचकांक में सम्मिलित करने की आवश्यकता है? - नहीं, DBMS तय करेगा कि इसे कहां रखा जाए, अगर मैं बिल्कुल जोड़ रहा हूं।

तो उन अतिरिक्त तरीकों के लिए मेरे पास क्या औचित्य होगा? (जो मेरे कार्मिक में वैसे भी लागू नहीं किया जाएगा)


निष्पक्ष बिंदु। मुझे लगता है कि मेरा प्रश्न विशिष्ट उदाहरण को संदर्भित करता है, जहां एक कोड की समीक्षा करते समय, मैं डीएओ को देखता हूं जो संग्रह लौटाते हैं, लेकिन मुझे पता है कि ये डीएओ कॉल हमेशा संस्थाओं के रिटर्निंग सेट होने जा रहे हैं; मेरा तर्क यह है कि इन मामलों में रिटर्न प्रकार विशिष्टता को इंगित करता है, और यह जानकारी उस विधि का उपयोग करने के लिए जो भी उपयोगी है (उदाहरण के लिए मुझे डुप्लिकेट की जांच करने की आवश्यकता नहीं है)।
Fil

यदि आपने एक DB को क्वेर किया है, तो 2 परिणामी वस्तुओं की बराबरी के साथ () बिल्कुल भी सही उत्पादन नहीं करना चाहिए - इसलिए आपको दोहराव के लिए वस्तुओं की तुलना करने के दूसरे तरीके की आवश्यकता होगी (उदाहरण के लिए, उनके पास एक ही नाम, एक ही आईडी है,) दोनों?)। आपको अपने DAO को यह बताने की आवश्यकता होगी कि यदि उनकी तुलना डुप्लिकेट को हटाने के लिए है, तो उनकी तुलना कैसे करें - लेकिन चूंकि आप उपयोगकर्ता हैं जो यह तय कर रहे हैं कि डुप्लिकेट मौजूद है या नहीं - बस कॉलिंग कोड से संग्रह के साथ इसे करना आसान है। (ग्रह पर हर संभव समानता की जांच करने के लिए डीएओ को सूचित करने के लिए अमूर्तता की अधिक परतों से बचने के लिए।)
मार्क एच

सहमत, लेकिन हम हाइबरनेट का उपयोग कर रहे हैं, और यह सुनिश्चित करते हैं कि हमारी इकाइयाँ बराबर () को लागू करें। इसलिए जब कोई DAO संस्थाओं को वापस कर रहा है, तो हम बहुत जल्दी से नया HashSet ()। AddAll (परिणाम) कर सकते हैं और वापस उस विधि को वापस ला सकते हैं।
Fil
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.