oop - विरासत बनाम एकत्रीकरण




inheritance language-agnostic (8)

ऑब्जेक्ट उन्मुख सिस्टम में कोड को सर्वोत्तम रूप से विस्तारित करने, बढ़ाने और पुन: उपयोग करने के तरीके के बारे में विचार के दो स्कूल हैं:

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

  2. एकत्रीकरण: अन्य वर्गों को ले कर और उन्हें एक नई कक्षा में जोड़कर नई कार्यक्षमता बनाएं। अन्य कोड के साथ अंतःक्रियाशीलता के लिए इस नई कक्षा में एक आम इंटरफेस संलग्न करें।

प्रत्येक के लाभ, लागत और परिणाम क्या हैं? क्या अन्य विकल्प हैं?

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


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

आगे के अंतर भी मौजूद हैं - सी ++ में निजी विरासत "संबंधों के संदर्भ में लागू किया गया है" इंगित करता है, जिसे भी (गैर-उजागर) सदस्य वस्तुओं के एकत्रीकरण द्वारा मॉडलिंग किया जा सकता है।


दोनों दृष्टिकोणों का उपयोग विभिन्न समस्याओं को हल करने के लिए किया जाता है। एक वर्ग से विरासत में होने पर आपको हमेशा दो या दो से अधिक कक्षाओं को एकत्रित करने की आवश्यकता नहीं होती है।

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



मुझे लगता है कि यह एक या / या बहस नहीं है। ये बस यही है:

  1. एक (विरासत) रिश्तों को एक (रचना) संबंधों से कम अक्सर होता है।
  2. विरासत सही होने के लिए कठिन है, भले ही इसका उपयोग करने के लिए उचित हो, इसलिए सावधानी बरतनी चाहिए क्योंकि यह encapsulation तोड़ सकता है, कार्यान्वयन को उजागर करके तंग युग्मन को प्रोत्साहित करता है और आगे।

दोनों की जगह है, लेकिन विरासत जोखिम भरा है।

यद्यपि निश्चित रूप से यह एक वर्ग आकार 'होने-ए' प्वाइंट और स्क्वायर कक्षाओं के लिए समझ में नहीं आता है। यहां विरासत देय है।

कुछ विस्तार करने की कोशिश करते समय लोगों को पहले विरासत के बारे में सोचना पड़ता है, यही गलत है।


मैं इसे मूल प्रश्न पर एक टिप्पणी करना चाहता था, लेकिन 300 वर्ण काटता है [; <)।

मुझे लगता है कि हमें सावधान रहना होगा। सबसे पहले, प्रश्न में किए गए दो विशिष्ट उदाहरणों की तुलना में अधिक स्वाद हैं।

साथ ही, मेरा सुझाव है कि साधन के साथ उद्देश्य को भ्रमित न करना मूल्यवान है। कोई यह सुनिश्चित करना चाहता है कि चुनी गई तकनीक या पद्धति प्राथमिक उद्देश्य की उपलब्धि का समर्थन करती है, लेकिन मुझे संदर्भ नहीं है कि तकनीक-सर्वोत्तम-सर्वोत्तम चर्चा बहुत उपयोगी है। यह उनके स्पष्ट मीठे धब्बे के साथ विभिन्न दृष्टिकोणों के नुकसान को जानने में मदद करता है।

उदाहरण के लिए, आप क्या हासिल करने के लिए बाहर हैं, आप किसके साथ शुरू करने के लिए उपलब्ध हैं, और बाधाएं क्या हैं?

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

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

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


मैं कहां-इन-हो सकता है-लागू भाग को कवर करूंगा। गेम परिदृश्य में, दोनों का एक उदाहरण यहां दिया गया है। मान लीजिए, एक ऐसा गेम है जिसमें विभिन्न प्रकार के सैनिक हैं। प्रत्येक सैनिक के पास एक नापसंद हो सकता है जो विभिन्न चीजों को पकड़ सकता है।

यहां विरासत? एक समुद्री, हरा beret और एक स्निपर है। ये सैनिकों के प्रकार हैं। तो, व्युत्पन्न कक्षाओं के रूप में समुद्री, ग्रीन बेरेट और स्निपर के साथ एक बेस क्लास सैनिक है

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


यह कोई बात नहीं है कि सबसे अच्छा क्या है, लेकिन इसका उपयोग कब किया जाए।

'सामान्य' मामलों में एक सरल सवाल यह पता लगाने के लिए पर्याप्त है कि हमें विरासत या एकत्रीकरण की आवश्यकता है या नहीं।

  • यदि नई कक्षा मूल वर्ग के रूप में कम या कम है। विरासत का प्रयोग करें। नई कक्षा अब मूल वर्ग का उप-वर्ग है।
  • यदि नई कक्षा में मूल वर्ग होना चाहिए। एकत्रीकरण का प्रयोग करें। नई कक्षा में अब सदस्य के रूप में मूल वर्ग है।

हालांकि, एक बड़ा भूरा क्षेत्र है। तो हमें कई अन्य चाल की जरूरत है।

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

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

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

चलिए एक उदाहरण जोड़ें। हमारे पास विधियों के साथ एक वर्ग 'कुत्ता' है: 'खाओ', 'चलना', 'छाल', 'प्ले'।

class Dog
  Eat;
  Walk;
  Bark;
  Play;
end;

अब हमें एक वर्ग 'बिल्ली' की जरूरत है, जिसे 'खाओ', 'वॉक', 'पुर', और 'प्ले' की आवश्यकता है। तो पहले इसे कुत्ते से विस्तारित करने का प्रयास करें।

class Cat is Dog
  Purr; 
end;

ठीक है, लेकिन प्रतीक्षा करें। यह बिल्ली बार्क कर सकती है (बिल्ली प्रेमियों ने मुझे इसके लिए मार डाला होगा)। और एक भौंकने वाली बिल्ली ब्रह्मांड के सिद्धांतों का उल्लंघन करती है। इसलिए हमें बार्क विधि को ओवरराइड करने की आवश्यकता है ताकि यह कुछ भी न करे।

class Cat is Dog
  Purr; 
  Bark = null;
end;

ठीक है, यह काम करता है, लेकिन यह बुरा गंध करता है। तो चलिए एकत्रीकरण आज़माएं:

class Cat
  has Dog;
  Eat = Dog.Eat;
  Walk = Dog.Walk;
  Play = Dog.Play;
  Purr;
end;

ठीक है, यह अच्छा है। यह बिल्ली अब और भी चुप नहीं है, यहां तक ​​कि चुप नहीं है। लेकिन फिर भी इसमें एक आंतरिक कुत्ता है जो बाहर निकलना चाहता है। तो चलिए समाधान संख्या तीन कोशिश करें:

class Pet
  Eat;
  Walk;
  Play;
end;

class Dog is Pet
  Bark;
end;

class Cat is Pet
  Purr;
end;

यह बहुत साफ है। कोई आंतरिक कुत्ते नहीं। और बिल्लियों और कुत्ते एक ही स्तर पर हैं। हम मॉडल का विस्तार करने के लिए अन्य पालतू जानवर भी पेश कर सकते हैं। जब तक यह एक मछली नहीं है, या कुछ ऐसा नहीं है जो चलता नहीं है। उस मामले में हमें फिर से प्रतिक्रिया करने की आवश्यकता है। लेकिन यह एक और समय के लिए कुछ है।


यहां मेरा सबसे आम तर्क है:

किसी वस्तु-उन्मुख प्रणाली में, किसी भी वर्ग में दो भाग होते हैं:

  1. इसका इंटरफ़ेस : ऑब्जेक्ट का "सार्वजनिक चेहरा"। यह उन क्षमताओं का सेट है जो इसे दुनिया के बाकी हिस्सों में घोषित करते हैं। कई भाषाओं में, सेट को "कक्षा" में अच्छी तरह से परिभाषित किया जाता है। आम तौर पर ये वस्तु के विधि हस्ताक्षर होते हैं, हालांकि यह भाषा द्वारा थोड़ा भिन्न होता है।

  2. इसका कार्यान्वयन : "दृश्यों के पीछे" काम करता है कि वस्तु अपने इंटरफेस को पूरा करने और कार्यक्षमता प्रदान करने के लिए करती है। यह आमतौर पर वस्तु का कोड और सदस्य डेटा होता है।

ओओपी के मौलिक सिद्धांतों में से एक यह है कि कार्यान्वयन कक्षा के भीतर encapsulated (यानी छुपा) है; बाहरी चीजों को देखना चाहिए केवल एक चीज इंटरफ़ेस है।

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

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

इसलिए, जब भी मैं ऑब्जेक्ट उन्मुख सॉफ्टवेयर विकसित कर रहा हूं, मैं लगभग हमेशा विरासत पर एकत्रीकरण पसंद करता हूं।







aggregation