कम्पोजीशन ओवर इनहेरिटेंस

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

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

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

विरासत
सी ++ में एक उदाहरण इस प्रकार है:

<वाक्यविन्यास लैंग = सीपीपी> वर्ग वस्तु { जनता: आभासी शून्य अद्यतन { // नो-ऑप }

आभासी शून्य ड्रा { // नो-ऑप }

आभासी शून्य टक्कर (ऑब्जेक्ट ऑब्जेक्ट्स []) { // नो-ऑप } };

वर्ग दृश्यमान: सार्वजनिक वस्तु {   मॉडल * मॉडल;

जनता: आभासी शून्य ड्रा ओवरराइड { // कोड इस वस्तु की स्थिति पर एक मॉडल बनाने के लिए } };

क्लास सॉलिड: पब्लिक ऑब्जेक्ट { जनता: आभासी शून्य टक्कर (ऑब्जेक्ट ऑब्जेक्ट्स []) ओवरराइड { // अन्य वस्तुओं के साथ टकराव की जांच करने और प्रतिक्रिया करने के लिए कोड } };

जंगम वर्ग: सार्वजनिक वस्तु { जनता: आभासी शून्य अद्यतन ओवरराइड { // कोड इस वस्तु की स्थिति को अद्यतन करने के लिए } }; 

फिर, मान लीजिए कि हमारे पास ये ठोस वर्ग भी हैं:

ध्यान दें कि मल्टीपल इनहेरिटेंस खतरनाक है अगर सावधानी से लागू नहीं किया गया है क्योंकि इससे मल्टीपल इनहेरिटेंस#द डायमंड प्रॉब्लम हो सकती है। इसका एक समाधान इस तरह की कक्षाएं बनाना है VisibleAndSolid, VisibleAndMovable, VisibleAndSolidAndMovable, आदि हर आवश्यक संयोजन के लिए; हालाँकि, यह बड़ी मात्रा में दोहराव वाले कोड की ओर ले जाता है। C ++ मल्टीपल इनहेरिटेंस की डायमंड प्रॉब्लम को हल करने के लिए आभासी विरासत का उपयोग करता है।
 * कक्षा Player - जो है Solid, Movable और Visible
 * कक्षा Cloud - जो है Movable और Visible, लेकिन नहीं Solid
 * कक्षा Building - जो है Solid और Visible, लेकिन नहीं Movable
 * कक्षा Trap - जो है Solid, लेकिन नहीं Visible और न Movable

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

नामक एक अमूर्त वर्ग का परिचय दें VisibilityDelegate, उपवर्गों के साथ NotVisible और Visible, जो किसी वस्तु को खींचने का साधन प्रदान करता है:

<वाक्यविन्यास लैंग = सीपीपी> वर्ग दृश्यता प्रतिनिधि { जनता: आभासी शून्य ड्रा = 0; };

क्लास नॉटविजिबल: पब्लिक विजिबिलिटी डेलिगेट { जनता: आभासी शून्य ड्रा ओवरराइड { // नो-ऑप } };

वर्ग दृश्यमान: सार्वजनिक दृश्यता प्रतिनिधि { जनता: आभासी शून्य ड्रा ओवरराइड { // कोड इस वस्तु की स्थिति पर एक मॉडल बनाने के लिए } }; 

नामक एक अमूर्त वर्ग का परिचय दें UpdateDelegate, उपवर्गों के साथ NotMovable और Movable, जो किसी वस्तु को स्थानांतरित करने का साधन प्रदान करता है:

<वाक्यविन्यास लैंग = सीपीपी> वर्ग अद्यतन प्रतिनिधि { जनता: आभासी शून्य अद्यतन = 0; };

क्लास नॉटमूवेबल: पब्लिक अपडेटडिलेगेट { जनता: आभासी शून्य अद्यतन ओवरराइड { // नो-ऑप } };

क्लास मूवेबल: पब्लिक अपडेटडिलेगेट { जनता: आभासी शून्य अद्यतन ओवरराइड { // कोड इस वस्तु की स्थिति को अद्यतन करने के लिए } }; 

नामक एक अमूर्त वर्ग का परिचय दें CollisionDelegate, उपवर्गों के साथ NotSolid और Solid, जो किसी वस्तु से टकराने का साधन प्रदान करता है:

<वाक्यविन्यास लैंग = सीपीपी> वर्ग टकराव प्रतिनिधि { जनता: आभासी शून्य टक्कर (ऑब्जेक्ट ऑब्जेक्ट्स []) = 0; };

क्लास नॉटसॉलिड: पब्लिक कोलिशनडिलेगेट { जनता: आभासी शून्य टक्कर (ऑब्जेक्ट ऑब्जेक्ट्स []) ओवरराइड { // नो-ऑप } };

क्लास सॉलिड: पब्लिक कोलिशनडिलेगेट { जनता: आभासी शून्य टक्कर (ऑब्जेक्ट ऑब्जेक्ट्स []) ओवरराइड { // अन्य वस्तुओं के साथ टकराव की जांच करने और प्रतिक्रिया करने के लिए कोड } }; 

अंत में, नाम की एक कक्षा का परिचय दें Object इसकी दृश्यता को नियंत्रित करने के लिए सदस्यों के साथ (ए VisibilityDelegate), चलनशीलता (एक का उपयोग करके UpdateDelegate), और दृढ़ता (ए का उपयोग करके CollisionDelegate). इस वर्ग में ऐसी विधियाँ हैं जो इसके सदस्यों को सौंपती हैं, उदा। update बस पर एक विधि कहते हैं UpdateDelegate:

<वाक्यविन्यास लैंग = सीपीपी> वर्ग वस्तु {   दृश्यता प्रतिनिधि* _v; UpdateDelegate* _u; CollisionDelegate* _c;

जनता: ऑब्जेक्ट (दृश्यता प्रतिनिधि * v, अद्यतन प्रतिनिधि * यू, टकराव प्रतिनिधि * सी) : _वी (वी) , _तुम तुम)      , _सी (सी)    {}

शून्य अद्यतन { _यू-> अपडेट ; }

शून्य ड्रा { _v-> ड्रा ; }

शून्य टक्कर (ऑब्जेक्ट ऑब्जेक्ट्स []) { _c-> टकराना (ऑब्जेक्ट्स); } }; 

फिर, ठोस कक्षाएं दिखेंगी:

<वाक्यविन्यास लैंग = सीपीपी> क्लास प्लेयर: पब्लिक ऑब्जेक्ट { जनता: खिलाड़ी : ऑब्जेक्ट (नया दृश्यमान, नया चल , नया ठोस ) {}

// ... };

वर्ग धुआँ: सार्वजनिक वस्तु { जनता: धुआँ : ऑब्जेक्ट (नया दृश्यमान, नया मूवेबल , नया नॉटसॉलिड ) {}

// ... }; 

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

कुछ भाषाएँ, विशेष रूप से गो (प्रोग्रामिंग भाषा) और जंग (प्रोग्रामिंग भाषा), विशेष रूप से प्रकार की रचना का उपयोग करें।

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

उदाहरण के लिए, नीचे दिए गए सी # कोड में, वेरिएबल्स और विधियों के Employee बेस क्लास द्वारा विरासत में मिला है HourlyEmployee और SalariedEmployee व्युत्पन्न उपवर्ग। केवल Pay विधि को प्रत्येक व्युत्पन्न उपवर्ग द्वारा कार्यान्वित (विशेष) करने की आवश्यकता है। अन्य विधियों को आधार वर्ग द्वारा ही लागू किया जाता है, और इसके सभी व्युत्पन्न उपवर्गों द्वारा साझा किया जाता है; उन्हें फिर से लागू करने (ओवरराइड) या यहां तक ​​​​कि उपवर्ग परिभाषाओं में उल्लेख करने की आवश्यकता नहीं है।

<वाक्यविन्यास प्रकाश लैंग = csharp> // बेस क्लास सार्वजनिक सार वर्ग कर्मचारी {   // गुण संरक्षित स्ट्रिंग नाम {प्राप्त करें; तय करना; } संरक्षित इंट आईडी {प्राप्त करें; तय करना; } संरक्षित दशमलव भुगतान दर {प्राप्त करें; तय करना; } संरक्षित int घंटे काम किया { प्राप्त करें; }

// वर्तमान वेतन अवधि के लिए भुगतान प्राप्त करें सार्वजनिक सार दशमलव वेतन ; }

// व्युत्पन्न उपवर्ग पब्लिक क्लास प्रति घंटा कर्मचारी: कर्मचारी {   // वर्तमान वेतन अवधि के लिए भुगतान प्राप्त करें सार्वजनिक ओवरराइड दशमलव वेतन {       // काम किया गया समय घंटों में है वापसी के घंटे काम * वेतन दर; } }

// व्युत्पन्न उपवर्ग सार्वजनिक वर्ग के वेतनभोगी कर्मचारी: कर्मचारी {   // वर्तमान वेतन अवधि के लिए भुगतान प्राप्त करें सार्वजनिक ओवरराइड दशमलव वेतन {       // वेतन दर प्रति घंटे की दर के बजाय वार्षिक वेतन है वापसी के घंटे काम * वेतन दर / 2087; } } 

कमियों से बचना
ट्रेट्स (कंप्यूटर साइंस), mixin्स, (टाइप) एम्बेडिंग, या प्रोटोकॉल (ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग) एक्सटेंशन का उपयोग करके इस कमी से बचा जा सकता है।

कुछ भाषाएँ इसे कम करने के लिए विशिष्ट साधन प्रदान करती हैं:


 * सी शार्प (प्रोग्रामिंग लैंग्वेज) | सी # संस्करण 8.0 के बाद से डिफ़ॉल्ट इंटरफ़ेस तरीके प्रदान करता है जो शरीर को इंटरफ़ेस सदस्य को परिभाषित करने की अनुमति देता है।
 * डी (प्रोग्रामिंग भाषा) एक स्पष्ट उपनाम प्रदान करता है, यह घोषणा एक प्रकार के भीतर हर विधि और किसी अन्य निहित प्रकार के सदस्य को अग्रेषित कर सकती है।
 * डार्ट (प्रोग्रामिंग भाषा) डिफ़ॉल्ट कार्यान्वयन के साथ मिक्सिन प्रदान करता है जिसे साझा किया जा सकता है।
 * गो (प्रोग्रामिंग लैंग्वेज) टाइप एम्बेडिंग अग्रेषण विधियों की आवश्यकता से बचाती है।
 * जावा (प्रोग्रामिंग भाषा) संस्करण 8 के बाद से डिफ़ॉल्ट इंटरफ़ेस विधियाँ प्रदान करता है। प्रोजेक्ट लोम्बोक प्रतिनिधिमंडल का समर्थन करता है @Delegate प्रत्यायोजित क्षेत्र से सभी विधियों के नामों और प्रकारों को कॉपी करने और बनाए रखने के बजाय क्षेत्र पर एनोटेशन। * जूलिया (प्रोग्रामिंग भाषा) मैक्रोज़ का उपयोग अग्रेषण विधियों को उत्पन्न करने के लिए किया जा सकता है। Lazy.jl जैसे कई कार्यान्वयन मौजूद हैं और TypedDelegation.jl।
 * कोटलिन (प्रोग्रामिंग भाषा) में लैंग्वेज सिंटैक्स में डेलिगेशन पैटर्न शामिल है।
 * PHP लक्षणों (कंप्यूटर विज्ञान) का समर्थन करता है।
 * राकू (प्रोग्रामिंग भाषा) एक प्रदान करता है handles विधि अग्रेषण की सुविधा के लिए विशेषता।
 * रस्ट (प्रोग्रामिंग लैंग्वेज) डिफ़ॉल्ट कार्यान्वयन के साथ लक्षण प्रदान करता है।
 * स्काला (प्रोग्रामिंग भाषा) (संस्करण 3 के बाद से) किसी वस्तु के चयनित सदस्यों के लिए उपनामों को परिभाषित करने के लिए एक निर्यात खंड प्रदान करता है।
 * स्विफ्ट (प्रोग्रामिंग भाषा) एक्सटेंशन का उपयोग किसी प्रोटोकॉल के डिफ़ॉल्ट कार्यान्वयन को परिभाषित करने के लिए किया जा सकता है, बजाय किसी व्यक्तिगत प्रकार के कार्यान्वयन के।

अनुभवजन्य अध्ययन
2013 में 93 ओपन सोर्स जावा प्रोग्राम (अलग-अलग आकार के) के एक अध्ययन में पाया गया कि:

"While there is not huge opportunity to replace inheritance with composition (...), the opportunity is significant (median of 2% of uses [of inheritance] are only internal reuse, and a further 22% are only external or internal reuse).

Our results suggest there is no need for concern regarding abuse of inheritance (at least in open-source Java software), but they do highlight the question regarding use of composition versus inheritance. If there are significant costs associated with using inheritance when composition could be used, then our results suggest there is some cause for concern."

यह भी देखें

 * प्रतिनिधिमंडल पैटर्न
 * लिस्कोव प्रतिस्थापन सिद्धांत
 * वस्तु उन्मुख डिजाइन
 * वस्तु रचना
 * भूमिका-उन्मुख प्रोग्रामिंग
 * राज्य पैटर्न
 * रणनीति पैटर्न