इंटरफ़ेस में "वैकल्पिक तरीकों" के साथ जावा संग्रह क्यों लागू किया गया?


69

मेरे पहले कार्यान्वयन के दौरान जावा संग्रह ढांचे का विस्तार करते हुए, मुझे यह देखकर बहुत आश्चर्य हुआ कि संग्रह इंटरफ़ेस में वैकल्पिक के रूप में घोषित तरीके हैं। यदि असमर्थित है तो कार्यान्वयनकर्ता को UnsupportedOperationException को फेंकने की उम्मीद है। इसने मुझे तुरंत खराब एपीआई डिजाइन विकल्प के रूप में मारा।

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

यहाँ मुद्दों का एक उत्कृष्ट सारांश है

क्या एक अच्छा कारण था कि दो इंटरफेस के कार्यान्वयन के बजाय वैकल्पिक तरीकों को क्यों चुना गया?


IMO, एक अच्छा कारण नहीं है। सी ++ STL 80 के दशक की शुरुआत में Stepanov द्वारा बनाया गया था। हालाँकि, यह प्रयोज्य सी ++ टेम्पलेट सिंटैक्स द्वारा सीमित किया गया था, यह जावा संग्रह कक्षाओं की तुलना में स्थिरता और प्रयोज्य का एक विरोधाभास है।
केविन क्लाइन

जावा में C ++ STL 'पोर्टिंग' था। लेकिन यह कक्षा की गिनती में 5 गुना बड़ा था। इस दिमाग के साथ मैं इसे नहीं खरीदता कि बड़ा एक अधिक सुसंगत और प्रयोग करने योग्य है। docs.oracle.com/javase/6/docs/technotes/guides/collections/…
m3th0dman

@ m3th0dman यह जावा में बहुत बड़ा है क्योंकि जावा में C ++ टेम्पलेट्स की शक्ति के बराबर कुछ भी नहीं है।
केविन क्लाइन

हो सकता है कि यह सिर्फ कुछ अजीब शैली मैं विकसित किया है, लेकिन मेरे कोड सभी संग्रह के इलाज के लिए जाता है के रूप में "केवल पढ़ने", (अधिक सटीक, बस कुछ है जो आप गिनती या जिस पर आप पुनरावृति) को छोड़कर के लिए कुछ तरीकों कि वास्तव में संग्रह बना। वैसे भी शायद अच्छा अभ्यास (esp। के लिए संगोष्ठी)। और जिन वैकल्पिक तरीकों के बारे में इतने सारे शिकायतें मेरे लिए कभी कोई वास्तविक मुद्दा नहीं रहा है। और न ही जेनेरिक दुःस्वप्न "सुपर" और "एक मुद्दे के (कभी) किया गया है" फैली हुई है। बस सोच रहा था कि क्या अन्य लोग इस सामान्य प्रथा का उपयोग करते हैं?
user949300

जवाबों:


28

पूछे जाने वाले प्रश्न उत्तर प्रदान करता है। संक्षेप में, उन्होंने संशोधित, अपरिवर्तनीय दृश्य, डिलीट-ओनली, ऐड-ओनली, फिक्स्ड-लेंथ, अपरिवर्तनीय (थ्रेडिंग के लिए), और इसी तरह कार्यान्वित विकल्प विधियों के प्रत्येक संभावित सेट के लिए आवश्यक इंटरफेस के संभावित दहनशील विस्फोट को देखा।


6
अगर जावा के पास constC ++ जैसा कोई कीवर्ड होता तो यह सब टाला जाता।
इटियेन डे मार्टेल

@ एटिएन: बेहतर होगा कि पाइथन जैसे मेटाक्लासेस हों। तब आप प्रोग्राम को कम्बाइंड करने के लिए इंटरफेस की संख्या बना सकते हैं। कॉन्स्ट के साथ समस्या यह है कि यह आपको केवल एक या दो आयाम देता है vector<int>, const vector<int>, vector<const int>, const vector<const int>:। अब तक बहुत अच्छा है, लेकिन फिर आप ग्राफ़ को लागू करने का प्रयास करते हैं, और आप ग्राफ़ संरचना को स्थिर बनाना चाहते हैं, लेकिन नोड गुणन-योग्य है, आदि
नील जी

2
@ एटीन, फिर भी मेरी टू-डू सूची में "लर्न स्केल" को टक्कर देने के लिए!
glenviewjeff

2
जो मुझे समझ नहीं आ रहा है, उन्होंने ऐसा canतरीका क्यों नहीं बनाया, जो एक ऑपरेशन संभव होने पर परीक्षण करेगा? यह इंटरफ़ेस को सरल और तेज़ रखेगा।
मेहरदाद

3
@ एटीन डे मार्टल नॉनसेंस। यह कैसे दहनशील विस्फोट में मदद करेगा?
टॉम हॉल्टिन -

10

यह मुझे लगता है जैसे Interface Segregation Principleतब वापस नहीं आया था जैसा कि अब है; चीजों को करने का यह तरीका (यानी आपके इंटरफ़ेस में सभी संभावित ऑपरेशन शामिल हैं और आपके पास "पतित" विधियाँ हैं जो आपके लिए अपवाद नहीं हैं जो आपके लिए आवश्यक नहीं हैं) SOLID और ISP गुणवत्ता कोड के लिए वास्तविक मानक बनने से पहले लोकप्रिय थे।


2
एक गिरावट क्यों? किसी को ISP पसंद नहीं है?
वेन मोलिना

यह भी ध्यान देने योग्य है कि फ्रेमवर्क में जो विचरण का समर्थन करते हैं, इंटरफ़ेस के उन पहलुओं को अलग करने के लिए एक बड़ा लाभ है जो उन लोगों से सहसंयोजक या विपरीत हो सकते हैं जो मौलिक रूप से अपरिवर्तनीय हैं। यहां तक ​​कि अनुपस्थित ऐसे समर्थन, फ्रेमवर्क में जो प्रकार के क्षरण का उपयोग नहीं करते हैं, इंटरफ़ेस के अलग-अलग पहलुओं को अलग करने में मूल्य होता है जो टाइप-इंडिपेंडेंट होते हैं (उदाहरण Countके लिए किसी संग्रह को प्राप्त करने की अनुमति देता है बिना इस बात की चिंता किए कि इसमें किस प्रकार के आइटम शामिल हैं), लेकिन जावा जैसे टाइप-इरेज़र-बेस्ड फ्रेमवर्क में ऐसा कोई मुद्दा नहीं है।
Supercat

4

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

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

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

ध्यान दें कि "वैकल्पिक क्षमताओं" का अस्तित्व कुछ मामलों में एकत्र किए गए संग्रह को कुछ कार्यों को लागू करने की अनुमति देता है जो कि क्षमता से कहीं अधिक कुशल थे अगर कार्यान्वयन के अस्तित्व द्वारा परिभाषित किया गया था। उदाहरण के लिए, मान लें कि concatenateदो अन्य में से एक समग्र संग्रह बनाने के लिए एक विधि का उपयोग किया गया था, जिसमें से पहला 1,000,000 तत्वों के साथ एक एरेलेलिस्ट के रूप में हुआ था और जिनमें से अंतिम एक बीस-तत्व संग्रह था जो केवल शुरुआत से पुनरावृत्त हो सकता था। यदि संकलित संग्रह 1,000,013 वां तत्व (इंडेक्स 1,000,012) के लिए पूछा गया था, तो वह ArrayList से पूछ सकता है कि इसमें कितने आइटम हैं (यानी 1,000,000), अनुरोधित सूचकांक (12 उपज) से घटाएं, दूसरे से बारह तत्वों को पढ़ें और छोड़ें संग्रह, और फिर अगले तत्व वापस।

ऐसी स्थिति में, भले ही समग्र संग्रह में अनुक्रमणिका द्वारा किसी वस्तु को वापस करने का एक तात्कालिक तरीका नहीं होगा, लेकिन 1,000,013 वीं वस्तु के लिए समग्र संग्रह पूछना अभी भी व्यक्तिगत रूप से 1,000,013 वस्तुओं को पढ़ने और सभी को अनदेखा करने की तुलना में बहुत तेज़ होगा, लेकिन अंतिम एक।


@kevincline: क्या आप उद्धृत शब्दों से असहमत हैं? मैं उन साधनों के डिजाइन पर विचार करूंगा जिनके द्वारा इंटरफ़ेस कार्यान्वयन उनकी आवश्यक विशेषताओं और क्षमताओं का वर्णन कर सकते हैं, इंटरफ़ेस डिज़ाइन के सबसे महत्वपूर्ण पहलुओं में से एक है, हालांकि यह अक्सर बहुत ध्यान नहीं देता है। यदि किसी इंटरफ़ेस के अलग-अलग कार्यान्वयन में कुछ सामान्य कार्यों को पूरा करने के अलग-अलग इष्टतम तरीके होंगे, तो ग्राहकों के लिए एक साधन होना चाहिए जो प्रदर्शन के बारे में परवाह करते हुए परिदृश्यों में सर्वश्रेष्ठ दृष्टिकोण का चयन करें जहां यह मायने रखता है।
सुपरकैट

1
क्षमा करें, अधूरी टिप्पणी। मैं यह कहने वाला था कि "'एक संग्रह के बारे में पूछने के तरीके' ..." चलता है जो रन-टाइम के लिए एक संकलन-समय की जाँच होनी चाहिए।
केविन क्लाइन

@kevincline: ऐसे मामलों में, जिनमें ग्राहक को एक निश्चित क्षमता रखने की आवश्यकता होती है और इसके बिना नहीं रह सकते हैं, संकलन-समय जाँच सहायक हो सकता है। दूसरी ओर, ऐसी कई स्थितियाँ हैं जहाँ संग्रह में क्षमताएँ हो सकती हैं, जिनके आगे वे संकलन-समय की गारंटी दे सकते हैं। कुछ मामलों में, यह एक व्युत्पन्न इंटरफ़ेस जिसका अनुबंध निर्दिष्ट करता है कि सभी को वैध कार्यान्वयन के लिए फ़ायदेमंद साबित हो सकता व्युत्पन्न इंटरफ़ेस विशेष तरीकों जो आधार इंटरफ़ेस में वैकल्पिक हैं का समर्थन करना चाहिए, लेकिन मामलों में कोड या नहीं, कुछ संभाल करने में सक्षम हो जाएगा, जहां इसकी कुछ विशेषता है ...
सुपरकैट

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

2
आपके प्रस्ताव के साथ एक समस्या है: एक "पूछें तो करो" पैटर्न में एक संगामिती मुद्दा है यदि किसी वस्तु की क्षमताओं को उसके जीवनकाल के दौरान बदल सकते हैं। (यदि आपको किसी भी तरह से अपवाद का जोखिम उठाना पड़ रहा है, तो आप पूछने के लिए परेशान नहीं हो सकते ...)
झूमिनल

-1

मैं इसे मूल डेवलपर्स को बताऊंगा, बस फिर वापस बेहतर नहीं जानना चाहिए। हम 1998 से या जब जावा 2 और संग्रह पहली बार जारी किए गए थे, तब से OO डिजाइन में एक लंबा सफर तय कर चुके हैं। ओआरओपी के शुरुआती दिनों में ऐसा प्रतीत होता है कि स्पष्ट बुरा डिज़ाइन अब इतना स्पष्ट नहीं था।

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

बेशक, यह सभी जंगली अटकलें हैं, मुझे संदेह है कि हम कभी भी इसका उत्तर सुनिश्चित कर सकते हैं जब तक कि मूल संग्रह में से एक में झंकार न हो।


7
क्या कास्टिंग? यदि कोई विधि आपको लौटाती है Collectionऔर ए नहीं है MutableCollection, तो यह स्पष्ट संकेत है कि इसे संशोधित करने का मतलब नहीं है। मुझे नहीं पता कि किसी को उन्हें कास्ट करने की आवश्यकता क्यों होगी। अलग-अलग इंटरफेस होने का मतलब है कि आपको रन टाइम पर एक अपवाद प्राप्त करने के बजाय संकलन समय पर उन प्रकार की त्रुटियां मिलेंगी। इससे पहले कि आप त्रुटि प्राप्त करें, बेहतर।
एटिने डे मार्टेल

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

6
अगर मैं आपको केवल संग्रह पढ़ने के लिए देता हूं, तो इसलिए कि मैं इसे संशोधित नहीं करना चाहता। एक अपवाद को फेंकना और प्रलेखन पर भरोसा करना एक पैच की तरह बहुत कुछ का नरक लगता है। C ++ में, मैं केवल एक constऑब्जेक्ट वापस करूंगा , तुरंत उपयोगकर्ता को बता रहा हूं कि ऑब्जेक्ट को संशोधित नहीं किया जा सकता है।
एटिने डे मार्टेल

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