क्या यह Iterator
का अनुबंध तोड़ता है?
सं
जावा Iterator
दो "अनुबंध" लगाता है। पहला अनुबंध जावा इंटरफ़ेस स्वयं है, जो 3 विधियों की घोषणा करता है: hasNext()
, next()
, और remove()
। कोई भी वर्ग जो इस Iterator
इंटरफ़ेस को लागू करता है, उन विधियों को परिभाषित करना होगा।
hasNext()
[...] TRUE देता यात्रा अधिक तत्व हैं:
दूसरा अनुबंध Iterator
के व्यवहार को परिभाषित करता है। [...] next()
पुनरावृत्ति में अगला तत्व लौटाता है [और] NoSuchElementException
फेंकता है यदि पुनरावृत्ति में कोई और तत्व नहीं है।
यह संपूर्ण अनुबंध है।
यह सच है कि यदि अंतर्निहित XMLStreamReader
उन्नत है, तो यह आपके BoxIterator
और/या DrawerIterator
को गड़बड़ कर सकता है। वैकल्पिक रूप से, BoxIterator.next()
और/या DrawerIterator.next()
को गलत बिंदुओं पर कॉल करना पुनरावृत्ति को गड़बड़ कर सकता है। हालांकि, सही ढंग से का उपयोग किया गया है, जैसे ऊपर दिए गए आपके उदाहरण कोड में, यह कोड ठीक से काम करता है और कोड को बहुत सरल बनाता है। आपको केवल इटरेटर के उचित उपयोग को दस्तावेज करने की आवश्यकता है।
एक ठोस उदाहरण के रूप में, Scanner
कक्षा Iterator<String>
लागू करती है, और अभी तक कई अन्य विधियां हैं जो अंतर्निहित धारा को आगे बढ़ाती हैं। यदि Iterator
वर्ग द्वारा लगाए गए एक मजबूत अनुबंध मौजूद थे, तो Scanner
कक्षा स्वयं ही उल्लंघन कर रही है।
Ivan के रूप में अंक टिप्पणी में बाहर, boxList
प्रकार class BoxIterator implements Iterator<Box>, Iterable<Box>
का नहीं होना चाहिए। आप वास्तव में होना चाहिए:
class BoxList implements Iterable<Box> { ... }
class BoxIterator implements Iterator<Box> { ... }
BoxList boxList = ...;
for (Box box : boxList) {
for (Drawer drawer : box) {
drawer.getId()
}
}
एक वर्ग को लागू दोनों Iterable
और Iterator
तकनीकी रूप से गलत आपके उपयोग के मामले के लिए नहीं है होने है, यह भ्रम की स्थिति पैदा कर सकते हैं।
एक और संदर्भ में इस कोड पर विचार करें:
List<Box> boxList = Arrays.asList(box1, box2, box3, box4);
for(Box box : boxList) {
// Do something
}
for(Box box : boxList) {
// Do some more stuff
}
यहाँ, boxList.iterator()
, दो बार कहा जाता है बक्से की सूची पुनरावृत्ति दो बार के लिए दो अलग-अलग Iterator<Box>
उदाहरणों बनाने के लिए,। चूंकि boxList
कई बार पुनरावृत्त किया जा सकता है, प्रत्येक पुनरावृत्ति के लिए एक नया इटरेटर उदाहरण की आवश्यकता होती है।
अपने कोड में:
BoxIterator boxList = new BoxIterator(xml_stream);
for (Box box : boxList) {
for (Drawer drawer : box) {
drawer.getId();
}
}
क्योंकि आप एक धारा से अधिक पुनरावृत्ति कर रहे हैं, आप नहीं (धारा रीवाइंड, या निकाले वस्तुओं के भंडारण के बिना) एक ही नोड पर दूसरी बार पुनरावृति कर सकते हैं। एक दूसरी कक्षा/वस्तु की आवश्यकता नहीं है; वही वस्तु इटरटेबल और इटरेटर दोनों के रूप में कार्य कर सकती है ... जो आपको एक वर्ग/वस्तु बचाती है।
यह कहकर, समयपूर्व अनुकूलन सभी बुराइयों की जड़ है। एक वर्ग/वस्तु की बचत संभावित भ्रम के लायक नहीं है; आपको BoxIterator
को BoxList implements Iterable<Box>
, और BoxIterator implements Iterator<Box>
में विभाजित करना चाहिए।
आपका वर्णन 'Box.iterator' रिटर्न की तरह एक नया' DrawerIterator' लग रहा है और है कि यदि ऐसा है तो है अनुबंध टूट नहीं किया जाएगा, के बाद से 'ड्रॉवरइटरेटर' को मौजूदा बॉक्स के अंदर केवल तत्वों को वापस करना चाहिए। – Thomas
@ थॉमस 'बॉक्स.इटरेटर() 'प्रत्येक कॉल पर वही' ड्रावर इटरेटर 'वापस कर देगा, क्योंकि वे सभी एक ही अंतर्निहित धारा तक पहुंचेंगे। इसका तात्पर्य यह है कि 'Box.iterator') को पिछले कॉल द्वारा लौटाया गया 'ड्रॉवर इटरेटर' भी जादुई रूप से उन्नत होगा। सभी एक ही कर्सर की स्थिति में अंतर्निहित धारा तक पहुंचेंगे। – Roland
आह मैं देखता हूं। वह तब अनुबंध तोड़ देगा। क्या आपको हर कॉल पर एक ही उदाहरण वापस करने की ज़रूरत है? यदि आप हर बार एक नया उदाहरण वापस लेते हैं और अनुक्रमिक रूप से पुनरावृत्त करते हैं (यानी कोई यादृच्छिक पहुंच नहीं) इससे कोई फर्क नहीं पड़ता कि कर्सर की स्थिति उन्नत हो गई होगी या नहीं। एक बॉक्स पर पुनरावृत्त करने के बाद 'ड्रॉर्स उस बॉक्स पर आगे कॉल करें' 'ड्रावरइटरेटर के' हैनक्स्ट() 'को झूठी वापसी करनी चाहिए। – Thomas