माता-पिता पॉइंटर के लिए एक परिपत्र संदर्भ कब स्वीकार्य है?


24

यह स्टैक ओवरफ्लो प्रश्न एक बच्चे के बारे में है जो अपने माता-पिता के लिए एक पॉइंटर के माध्यम से संदर्भ देता है।

डिजाइन की शुरुआत में भयानक विचार के लिए टिप्पणियां काफी महत्वपूर्ण थीं।

मैं समझता हूं कि यह सामान्य तौर पर सबसे अच्छा विचार नहीं है। अंगूठे के एक सामान्य नियम से यह कहना उचित प्रतीत होता है, "ऐसा मत करो!"

हालाँकि, मैं सोच रहा हूँ कि किस तरह की स्थितियाँ होंगी जहाँ आपको ऐसा कुछ करने की आवश्यकता होगी। यहाँ यह प्रश्न और उससे जुड़े उत्तर / कमेंट्री ग्राफ़ के लिए भी सुझाव देते हैं कि ऐसा कुछ न किया जाए।


1
आपके द्वारा जोड़ा गया प्रश्न इस विषय पर बहुत व्यापक लगता है।
मोनिका

4
@LightnessRacesinOrbit "ऐसा न करें" वास्तव में जहां तक ​​समझ में नहीं आता है, उपयोगी नहीं है ।
एंडरलैंड

2
मैं वहाँ "यह मत करो" की तुलना में बहुत अधिक देखता हूं। मुझे कई विशेषज्ञों द्वारा पेशेवरों और बहस पर बहस होती है।
मोनिका

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

2
अंगूठे का मेरा व्यावहारिक नियम एक सवाल है "क्या कोई बच्चा बिना माता-पिता के मौजूद हो सकता है?"। (यदि आप XmlDocuments और इसके नोड्स पर विचार करते हैं: एक नोड एक दस्तावेज़ के पेड़ के संदर्भ के बिना मौजूद नहीं हो सकता है। यह एक बकवास है)। यदि उत्तर नहीं है तो द्वि-दिशात्मक लिंक ठीक हैं: आपके पास दो ऑब्जेक्ट हैं जो केवल एक साथ मौजूद हो सकते हैं। यदि ऑब्जेक्ट स्वतंत्र रूप से मौजूद हो सकते हैं, तो मैं उन दो लिंक में से एक को हटा देता हूं।
मिकलाई '

जवाबों:


43

यहां कुंजी यह नहीं है कि क्या दो वस्तुओं में परिपत्र संदर्भ हैं, लेकिन क्या वे संदर्भ एक दूसरे के स्वामित्व का संकेत देते हैं ।

दो वस्तुएं एक-दूसरे को "खुद" नहीं कर सकती हैं: यह आरंभीकरण और विलोपन आदेश के लिए एक अचूक दुविधा का कारण बनता है। एक वैकल्पिक संदर्भ होना चाहिए, या अन्यथा इंगित करें कि एक वस्तु दूसरे के जीवनकाल का प्रबंधन नहीं करेगी।

एक डबल-लिंक्ड सूची पर विचार करें: दो नोड्स एक-दूसरे से आगे और पीछे लिंक करते हैं, लेकिन न तो दूसरे का "मालिक" है (सूची दोनों का मालिक है)। इसका मतलब यह है कि न तो नोड दूसरे के लिए स्मृति आवंटित करता है या अन्यथा अन्य की पहचान या जीवनकाल प्रबंधन के लिए जिम्मेदार है।

पेड़ों का एक समान संबंध है, हालांकि एक पेड़ में नोड्स बच्चों को आवंटित कर सकते हैं और माता-पिता खुद बच्चे करते हैं। एक बच्चे से माता-पिता के लिए लिंक ट्रैवर्सल में मदद करता है, लेकिन फिर से स्वामित्व को परिभाषित नहीं करता है।

अधिकांश OO डिज़ाइन में, ऑब्जेक्ट के डेटा सदस्य के रूप में किसी अन्य ऑब्जेक्ट का संदर्भ स्वामित्व का अर्थ है। उदाहरण के लिए, मान लीजिए कि हमारे पास कार और इंजन हैं। न ही कोई अपने आप में बहुत उपयोगी है। हम कह सकते हैं कि ये वस्तुएं एक-दूसरे पर निर्भर हैं : उपयोगी कार्य करने के लिए उन्हें दूसरे की उपस्थिति की आवश्यकता होती है। लेकिन जो दूसरे का "मालिक" है? इस मामले में हम कहेंगे कि कार इंजन का मालिक है क्योंकि कार "कंटेनर" है जिसमें सभी ऑटोमोटिव घटक रहते हैं। एक OO और वास्तविक दुनिया के डिजाइन दोनों में, कार अपने भागों का योग है, और उन सभी भागों को कार के संदर्भ में एक साथ जोड़ा जाता है। इंजन में कार के लिए एक संदर्भ हो सकता है, या उसके पास टॉर्ककॉर्टर का संदर्भ हो सकता है,

परिपत्र संदर्भ एक खराब डिजाइन गंध हो सकता है, लेकिन जरूरी नहीं। जब विवेकपूर्ण तरीके से और सही ढंग से प्रलेखित किया जाता है, तो वे डेटा संरचनाओं का उपयोग करना आसान बना सकते हैं।

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


16

इस तरह के डिजाइन में विचार करने के लिए कई पहलू हैं:

  • संरचनात्मक निर्भरताएँ
  • मालिकाना संबंध (iecomposition बनाम अन्य प्रकार के सहयोगी)
  • नेविगेशन की जरूरत है

कक्षाओं के बीच संरचनात्मक निर्भरता:

यदि आप घटक कक्षाओं के पुन: उपयोग का लक्ष्य रखते हैं, तो आपको अनावश्यक निर्भरता से बचना चाहिए और इस तरह के बंद परिपत्र संरचनाओं से बचना चाहिए।

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

वस्तुओं का स्वामित्व:

क्या एक वस्तु दूसरे का मालिक है? या अन्यथा कहा गया है: यदि एक वस्तु नष्ट हो जाती है, तो दूसरी भी नष्ट हो जाएगी?

यह विषय स्नोमैन द्वारा गहराई से संबोधित किया गया था, इसलिए मैं इसे यहां संबोधित नहीं करने जा रहा हूं।

वस्तुओं के बीच नेविगेशन की जरूरत:

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

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

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

बेशक, जैसा कि गामा और अल ने बताया, आपको परिपत्र संबंध के आक्रमणकारियों को सुनिश्चित करना होगा। यह मुश्किल हो सकता है, क्योंकि एसओ प्रश्न जो आपने दिखाया है। लेकिन यह पूरी तरह से प्रबंधनीय और सुरक्षित तरीके से है।

निष्कर्ष

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

एकमात्र बिंदु यह है कि कभी-कभी लोग जल्दी से ऐसी दिशा में जाते हैं। तो इसके लिए जाने के निर्णय लेने से पहले शामिल सभी 3 पहलुओं पर विचार करना लायक है या नहीं।


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

@DocBrown - इस पात्र के बन जाने पर आप हमेशा इस सवाल पर ध्यान रख सकते हैं। :-)

1
@ GlenH7: जो इस जवाब को अधिक वोट नहीं देगा, केवल स्नोमैन का जवाब (जिसके लिए मुझे लगता है कि यह सवाल का कुछ हद तक याद आता है)।
डॉक ब्राउन

1
@DocBrown - लेकिन रेपज़, यार, रेपज़!

... और यदि आप सार्वजनिक-निजी-संरक्षित जैसे दृश्यता विकल्प जोड़ते हैं, तो इससे आपको 9 अलग-अलग विकल्प
मिलेंगे

8

आमतौर पर, परिपत्र संदर्भ एक बहुत बुरा विचार है क्योंकि उनका मतलब परिपत्र निर्भरता है। आप शायद पहले से ही जानते हैं कि परिपत्र अवसाद क्यों खराब हैं, लेकिन पूर्णता की खातिर, टीएल; ड्र; संस्करण यह है कि जब भी ए और बी दोनों कक्षाएं एक-दूसरे पर निर्भर करती हैं, तो ए / बी को समझना / ठीक करना / अनुकूलित करना आदि असंभव है। एक ही समय में अन्य वर्ग को समझना / ठीक करना / अनुकूलित करना / आदि। जो जल्दी से कोडबेस की ओर जाता है जहाँ आप सब कुछ बदले बिना कुछ भी नहीं बदल सकते।

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


6

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

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


5

[...] कुछ भी ऐसा न करने के लिए रेखांकन के लिए भी सुझाव देता है।

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

एक उदाहरण के रूप में, एक quadtree वेक्टर ग्राफिक्स सॉफ्टवेयर में तत्वों को संग्रहीत कर सकता है। हालाँकि, उपयोगकर्ता के चयन को वेक्टर तत्व संदर्भों / बिंदुओं की एक अलग चयन सूची में संग्रहीत किया जाता है। जब उपयोगकर्ता उस चयन को हटाना चाहता है, तो हमें क्वाडट्री को अपडेट करना होगा, और नीचे-ऊपर की बजाय पत्तियों से शुरू होने वाले पेड़ में पेड़ को अपडेट करने के लिए पूरी तरह से अधिक कुशल होना चाहिए। अन्यथा, आपको प्रत्येक तत्व के लिए, रूट से लीफ तक काम करना होगा और फिर फिर से बैकअप लेना होगा।


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

@Christophe मुझे भी आपका उदाहरण पसंद है! मुझे यकीन नहीं था कि मैं वास्तव में सवाल का ठीक से जवाब दे रहा था क्योंकि शायद यह "बैकवर्ड पॉइंटर्स" की तुलना में "परिपत्र स्वामित्व" के बारे में अधिक था जो हमें एक डेटा संरचना को पीछे / पीछे की ओर ले जाने देता है। लेकिन मैं मुख्य रूप से प्रश्न के उस अंतिम "ग्राफ" भाग का जवाब दे रहा था।

2

Doom 3 में एक पेरेंट ऑब्जेक्ट के लिए पॉइंटर के साथ एक चाइल्ड ऑब्जेक्ट का एक उदाहरण है। विशेष रूप से यह घुसपैठ सूचियों का उपयोग करता है । सारांशित करने के लिए, एक घुसपैठ सूची एक लिंक की गई सूची की तरह है, प्रत्येक नोड को छोड़कर सूची में एक संकेतक होता है।

लाभ:

  • जब ऑब्जेक्ट एक साथ कई सूचियों में मौजूद हो सकते हैं, तो सूची नोड्स के लिए मेमोरी को केवल एक बार आवंटित और निपटाया जाना चाहिए।

  • जब किसी ऑब्जेक्ट को नष्ट करने की आवश्यकता होती है, तो आप इसे आसानी से उन सभी सूचियों से हटा सकते हैं, जो बिना प्रत्येक सूची के रैखिक रूप से खोजे बिना हैं।

मुझे लगता है कि यह एक बहुत विशिष्ट परिदृश्य है, लेकिन अगर मैं आपके प्रश्न को समझता हूं, तो यह एक बच्चे के ऑब्जेक्ट के स्वीकार्य उपयोग का उदाहरण है, जिसमें उसके मूल ऑब्जेक्ट के लिए पॉइंटर होता है।

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