क्या कोई "वास्तविक" कारण कई विरासत से नफरत है?


123

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

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

बस इस समस्या के बारे में पता होना लड़ाई का 90% है। इसके अलावा मुझे लगता है कि मैंने कुछ साल पहले एक सामान्य-प्रयोजन के काम के बारे में सुना था, जिसमें एक "लिफाफा" एल्गोरिथ्म शामिल था या ऐसा कुछ (क्या यह घंटी बजाता है, किसी को भी?)।

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

तो यह सब कहा जा रहा है ... क्या कोई वास्तविक कारण है कि ज्यादातर लोग कई विरासत से नफरत करते हैं, या क्या यह सब उन्माद का एक गुच्छा है जो अच्छे से अधिक नुकसान पहुंचाता है? क्या ऐसा कुछ है जो मैं यहाँ नहीं देख रहा हूँ? धन्यवाद।

उदाहरण

कार WheeledVehicle तक फैली हुई है, KIASpectra कार और इलेक्ट्रॉनिक का विस्तार करती है, KIASpectra में रेडियो शामिल है। KIASpectra में इलेक्ट्रॉनिक क्यों नहीं है?

  1. क्योंकि यह है एक इलेक्ट्रॉनिक। विरासत बनाम रचना हमेशा एक-एक संबंध बनाम एक-एक संबंध होना चाहिए।

  2. क्योंकि यह है एक इलेक्ट्रॉनिक। उस चीज़ के ऊपर और नीचे तार, सर्किट बोर्ड, स्विच आदि होते हैं।

  3. क्योंकि यह है एक इलेक्ट्रॉनिक। यदि आपकी बैटरी सर्दियों में मृत हो जाती है, तो आप बस इतनी परेशानी में हैं जैसे कि आपके सभी पहिये अचानक गायब हो गए हों।

इंटरफेस का उपयोग क्यों नहीं करते? उदाहरण के लिए # 3 लें। मैं इसे बार-बार लिखना नहीं चाहता, और मैं वास्तव में ऐसा करने के लिए कुछ विचित्र छद्म सहायक वर्ग बनाना नहीं चाहता:

private void runOrDont()
{
    if (this.battery)
    {
        if (this.battery.working && this.switchedOn)
        {
            this.run();
            return;
        }
    }
    this.dontRun();
}

(हम इस बात पर विचार नहीं कर रहे हैं कि यह कार्यान्वयन अच्छा है या बुरा है।) आप कल्पना कर सकते हैं कि इलेक्ट्रॉनिक से जुड़े ऐसे कई कार्य कैसे हो सकते हैं जो कि व्हीलेवेडिकल और वाइस-वर्सा में किसी भी चीज़ से संबंधित नहीं हैं।

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


24
यह रचना पर वंशानुक्रम को भी प्रोत्साहित करता है ... (जब यह चारों ओर का दूसरा रास्ता होना चाहिए)
शाफ़्ट फ्रीक

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

8
कई भाषाओं में एकाधिक वंशानुक्रम के लिए सुरक्षित विकल्प हैं, जो इंटरफेस से परे हैं। स्कैला की जांच करें Traits- वे वैकल्पिक कार्यान्वयन के साथ इंटरफेस की तरह काम करते हैं, लेकिन कुछ प्रतिबंध हैं जो हीरे की समस्या जैसे मुद्दों को उत्पन्न होने से रोकने में मदद करते हैं।
KChaloux

5
पूर्व में बंद किए गए इस प्रश्न को भी देखें: प्रोग्रामर.स्टैकएक्सचेंज.
डॉक ब्राउन

19
KiaSpectraनहीं है Electronic ; यह है इलेक्ट्रॉनिक्स, और एक हो सकता है ElectronicCar(विस्तार होगा जो Car...)
ब्रायन एस

जवाबों:


68

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

हालाँकि, पक्षी अन्य लक्षण है कि Pegasi नहीं है। उदाहरण के लिए, पक्षी अंडे देते हैं, पेगासी ने जीवित जन्म लिया है। यदि वंशानुक्रम आपके साझाकरण लक्षणों को पारित करने का एकमात्र साधन है, तो पेगासस से अंडा बिछाने के निशान को बाहर करने का कोई तरीका नहीं है।

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

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

एक आयत से विरासत में मिले वर्ग का क्लासिक उदाहरण लें। आयत एक लंबाई और चौड़ाई की संपत्ति को उजागर करती है और एक गेटपैरमीटर और गेटआरे विधि भी है। वर्ग लंबाई और चौड़ाई को ओवरराइड करेगा ताकि जब एक सेट हो तो दूसरा गेटपैरिमेट से मिलान करने के लिए सेट हो जाए और गेटआरे परिधि के लिए समान (2 * लंबाई + 2 * चौड़ाई और क्षेत्र के लिए चौड़ाई) काम करेगा।

एक एकल परीक्षण मामला है जो टूटता है यदि आप आयत के लिए एक वर्ग के इस कार्यान्वयन को प्रतिस्थापित करते हैं।

var rectangle = new Square();
rectangle.length= 5;
rectangle.width= 6;
Assert.AreEqual(30, rectangle.GetArea()); 
//Square returns 36 because setting the width clobbers the length

यह एक एकल वंशानुक्रम श्रृंखला के साथ चीजों को प्राप्त करने के लिए पर्याप्त कठिन है। यह और भी बुरा हो जाता है जब आप मिश्रण में एक और जोड़ते हैं।


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

और मैं इस बात से सहमत हूं कि मैं कुछ हद तक "वास्तविक दुनिया" के साथ धोखा कर रहा हूं कि एमआई को क्यों फंसाया जाता है।

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

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

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

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

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

उम्मीद है कि इस बात पर थोड़ी अधिक जानकारी दी गई कि मल्टीपल इनहेरिटेंस आमतौर पर क्यों होता है।


14
"यार मुझे वास्तव में एमआई को ठीक से करने की ज़रूरत है" - एक निर्वासन के लिए मेरा जवाब देखें। संक्षेप में, एक-एक संबंध को संतुष्ट करने वाले ऑर्थोगोनल अवधारणाएं एमआई के लिए समझ में आती हैं। वे बहुत दुर्लभ हैं, लेकिन वे मौजूद हैं।
MrFox

13
यार, मैं उस वर्ग आयत उदाहरण से नफरत करता हूं। ऐसे बहुत से रोशन उदाहरण हैं जिनके लिए परिवर्तनशीलता की आवश्यकता नहीं है।
asmeurer

9
मुझे यह पसंद है कि "एक वास्तविक उदाहरण प्रदान करने" का जवाब एक काल्पनिक प्राणी पर चर्चा करना था। उत्कृष्ट विडंबना +1
jjathman

3
तो आप कह रहे हैं कि कई उत्तराधिकार बुरे हैं, क्योंकि वंशानुक्रम खराब है (आप उदाहरण एकल इंटरफ़ेस वंशानुक्रम के बारे में हैं)। इसलिए, अकेले इस उत्तर के आधार पर, एक भाषा को या तो विरासत और इंटरफेस से छुटकारा पाना चाहिए, या कई विरासत चाहिए।
ctrl-alt-delor-delor

12
मुझे नहीं लगता कि ये उदाहरण वास्तव में काम करते हैं ... कोई नहीं कहता है कि एक पेगासस एक पक्षी और एक घोड़ा है ... आप कहते हैं कि यह एक विंग्डनिमल और एक हॉफेडअनिमल है। वर्ग और आयत का उदाहरण थोड़ा अधिक समझ में आता है क्योंकि आप अपने आप को एक ऐसी वस्तु के साथ पाते हैं जो अलग तरह से व्यवहार करती है, जैसा कि आप अपनी अनुमानित परिभाषा के आधार पर सोचते हैं। हालाँकि, मुझे लगता है कि इस स्थिति को पकड़ने के लिए प्रोग्रामर की गलती होगी (यदि वास्तव में यह समस्या साबित हुई)।
रिचर्ड

60

क्या ऐसा कुछ है जो मैं यहाँ नहीं देख रहा हूँ?

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

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

इस अन्य मामले में, आपके पास 3 परिदृश्य हैं:

  1. A, B - Great के बारे में कुछ नहीं जानता है, आप कक्षाओं को जोड़ सकते हैं क्योंकि आप भाग्यशाली थे।
  2. A, B के बारे में जानता है - A ने B से केवल वंशानुक्रम क्यों नहीं लिया?
  3. A और B एक दूसरे के बारे में जानते हैं - आपने सिर्फ एक वर्ग क्यों नहीं बनाया? इन चीज़ों को इतना युग्मित लेकिन आंशिक रूप से बदली बनाने से क्या लाभ होता है?

व्यक्तिगत रूप से, मुझे लगता है कि कई विरासत में एक बुरा रैप है, और यह कि विशेषता शैली संरचना की एक अच्छी तरह से किया गया सिस्टम वास्तव में शक्तिशाली / उपयोगी होगा ... लेकिन बहुत सारे तरीके हैं जो इसे बुरी तरह से लागू किया जा सकता है, और बहुत सारे कारण हैं C ++ जैसी भाषा में अच्छा विचार नहीं है।

[संपादित करें] अपने उदाहरण के बारे में, यह बेतुका है। एक किआ में इलेक्ट्रॉनिक्स है। यह है एक इंजन। इसी तरह, यह इलेक्ट्रॉनिक्स का एक शक्ति स्रोत है, जो सिर्फ कार बैटरी होने के लिए होता है। वंशानुक्रम, अकेले कई वंशानुक्रम का वहाँ कोई स्थान नहीं है।


8
एक और दिलचस्प सवाल यह है कि आधार वर्ग + उनके आधार वर्गों को कैसे आरंभ किया जाता है। एनकैप्सुलेशन> वंशानुक्रम।
जोजफग

"विशेषता शैली रचना की एक अच्छी तरह से किया प्रणाली वास्तव में शक्तिशाली / उपयोगी होगा ..." - ये रूप में जाना जाता हैं mixins , और वे कर रहे हैं शक्तिशाली / उपयोगी। मिक्स का उपयोग करके मिश्रण को लागू किया जा सकता है, लेकिन मिश्रण के लिए मल्टीपल इनहेरिटेंस की आवश्यकता नहीं है। कुछ भाषाएँ मिक्स के बिना, स्वाभाविक रूप से मिक्सी का समर्थन करती हैं।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

विशेष रूप से जावा के लिए, हमारे पास पहले से ही कई इंटरफेस हैं और इनवोकेंटरफेस हैं, इसलिए एमआई के पास कोई स्पष्ट प्रदर्शन प्रभाव नहीं होगा।
डैनियल लुबरोव

Tetastyn, मैं मानता हूं कि उदाहरण खराब था और उसने अपने प्रश्न की सेवा नहीं की। वंशानुक्रम विशेषण (इलेक्ट्रॉनिक) के लिए नहीं है, यह संज्ञा (वाहन) के लिए है।
रिचार्ड

29

एकमात्र कारण यह है कि इसे अस्वीकृत कर दिया गया है, क्योंकि यह लोगों के लिए खुद को पैर में गोली मारना आसान बनाता है।

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

यदि आपके डेवलपर्स एमआई के साथ सहज हैं, और एमआई आपके द्वारा किए जा रहे काम के संदर्भ में समझ में आता है, तो आप इसे संभवतः ऐसी भाषा में याद करेंगे जो इसका समर्थन नहीं करती है। उसी समय यदि टीम इसके साथ सहज नहीं है, या इसकी कोई वास्तविक आवश्यकता नहीं है और लोग इसे 'सिर्फ इसलिए कि वे कर सकते हैं' का उपयोग करते हैं, तो वह प्रति-उत्पादक है।

लेकिन नहीं, वहाँ एक सर्व-मान्य पूर्ण सत्य तर्क मौजूद नहीं है जो एकाधिक उत्तराधिकार को एक बुरा विचार साबित करता है।

संपादित करें

इस प्रश्न के उत्तर सर्वसम्मत प्रतीत होते हैं। शैतान के वकील होने की खातिर मैं कई विरासत का एक अच्छा उदाहरण प्रदान करूंगा, जहां ऐसा नहीं करने से हैक की ओर जाता है।

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

यहां समस्या यह है कि इन मौलिक प्रकारों को किसी भी क्रमपरिवर्तन में मिलाया जा सकता है जो स्वाभाविक रूप से एक को दूसरे से प्राप्त नहीं करता है। वस्तुओं को एक संबंध द्वारा परिभाषित किया जाता है , इसलिए रचना कोई मतलब नहीं रखती है। मल्टीपल इनहेरिटेंस (या मिक्सिन्स की समान अवधारणा) यहाँ केवल तार्किक प्रतिनिधित्व है।

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


27
मैंने फाइनेंस में काम किया है। वित्तीय सॉफ्टवेयर में OO पर कार्यात्मक प्रोग्रामिंग को प्राथमिकता दी जाती है। और आपने इसे इंगित किया है। एमआई इस समस्या को ठीक नहीं करता है जो इसे बढ़ा देता है। मेरा विश्वास करो मैं आपको यह नहीं बता सकता कि मैंने कितनी बार सुना है "यह ऐसा ही है ... सिवाय" "जब वित्त ग्राहकों के साथ व्यवहार किया जाता है, सिवाय इसके कि मेरे अस्तित्व का प्रतिबंध बन जाता है।
माइकल ब्राउन

8
यह मेरे लिए इंटरफेस के साथ बहुत सॉल्विंग लगता है ... वास्तव में, यह किसी भी चीज की तुलना में इंटरफेस के लिए बेहतर अनुकूल लगता है। Equityऔर Debtदोनों लागू होते हैं ISecurityDerivativeएक ISecurityसंपत्ति है। यह स्वयं एक ISecurityउचित हो सकता है (मैं वित्त नहीं जानता)। IndexedSecuritiesफिर से एक इंटरफ़ेस प्रॉपर्टी होती है, जो उन प्रकारों पर लागू होती है, जिनके आधार पर इसे अनुमति दी जाती है। यदि वे सभी हैं ISecurity, तो उन सभी में ISecurityगुण हैं और मनमाने ढंग से नेस्टेड किया जा सकता है ...
बोबसन

11
@ बोबसन समस्या यह है कि आपको प्रत्येक कार्यान्वयनकर्ता के लिए इंटरफ़ेस को फिर से लागू करना होगा, और कई मामलों में यह केवल एक ही है। आप प्रतिनिधिमंडल / रचना का उपयोग कर सकते हैं, लेकिन फिर आप निजी सदस्यों तक पहुँच खो देते हैं। और चूँकि जावा में डेलीगेट्स / लैम्ब्डा नहीं हैं ... ऐसा करने का कोई अच्छा तरीका नहीं है। संभवतः एस्पेक्ट 4 जे जैसे एक एस्पेक्ट टूल को छोड़कर
माइकल ब्राउन

10
@ बोबसन ने वास्तव में माइक ब्राउन ने क्या कहा। हां, आप इंटरफेस के साथ एक समाधान डिज़ाइन कर सकते हैं, लेकिन यह क्लंकी होगा। इंटरफेस का उपयोग करने का आपका अंतर्ज्ञान बहुत सही है, हालांकि, यह मिक्सिन्स / मल्टीपल इनहेरिटेंस :) की छिपी हुई इच्छा है।
20

11
यह एक विषमता को छूता है जहां OO प्रोग्रामर विरासत के संदर्भ में सोचना पसंद करते हैं और यह प्रतिनिधिमंडल को मान्य OO दृष्टिकोण के रूप में स्वीकार करने में विफल रहता है, जो आमतौर पर अधिक दुबला और अधिक टिकाऊ और एक्स्टेंसिबल समाधान प्राप्त करता है। वित्त और स्वास्थ्य सेवा में काम करने के बाद, मैंने देखा है कि असहनीय गड़बड़ी एमआई बना सकती है, विशेष रूप से कर और स्वास्थ्य कानून साल दर साल बदलते हैं और एक वस्तु की परिभाषा कम से कम वर्ष THIS वर्ष के लिए अमान्य है (फिर भी अभी भी वर्ष का कार्य करना चाहिए , और विनिमेय होना चाहिए)। रचना से लीनर कोड की पैदावार होती है जो परीक्षण के लिए आसान है, और यह समय के साथ कम खर्च करता है।
शॉन विल्सन

11

यहाँ अन्य उत्तर अधिकतर सिद्धांत में मिलते हैं। तो यहाँ एक ठोस पायथन उदाहरण है, सरलीकृत किया गया है, कि मैं वास्तव में हेडलंग में धँसा हुआ हूँ, जिसे उचित मात्रा में परावर्तन की आवश्यकता है:

class Foo(object):
   def zeta(self):
      print "foozeta"

class Bar(object):
   def zeta(self):
      print "barzeta"

   def barstuff(self):
      print "barstuff"
      self.zeta()

class Bang(Foo, Bar):
   def stuff(self):
      self.zeta()
      print "---"
      self.barstuff()

z = Bang()
z.stuff()

Barयह मानते हुए लिखा गया था कि इसका अपना कार्यान्वयन है zeta(), जो आम तौर पर एक बहुत अच्छी धारणा है। एक उपवर्ग को इसे उचित रूप से ओवरराइड करना चाहिए ताकि यह सही काम करे। दुर्भाग्य से, नाम केवल संयोग से एक ही थे - उन्होंने अलग-अलग चीजें कीं, लेकिन Barअब इसे Fooलागू कर रहे थे:

foozeta
---
barstuff
foozeta

जब कोई त्रुटि नहीं होती है तो यह निराशाजनक होता है, एप्लिकेशन केवल इतना थोड़ा गलत काम करना शुरू कर देता है, और कोड परिवर्तन जिसके कारण यह (निर्माण Bar.zeta) होता है, जहां समस्या निहित नहीं है।


कैसे कॉल के माध्यम से हीरे की समस्या से बचा जाता है super()?
पैंजरक्रिसिस

@Panzercrisis क्षमा करें, उस हिस्से को कभी भी न रखें। मैंने गलत तरीके से बताया कि "डायमंड की समस्या" किस समस्या को संदर्भित करती है - पायथन में हीरे के आकार की विरासत के कारण एक अलग मुद्दा था जो super()लगभग मिला
इज़काता

5
मुझे खुशी है कि C ++ का MI बेहतर डिज़ाइन किया गया है। उपरोक्त बग बस संभव नहीं है। कोड संकलित करने से पहले आपको इसे मैन्युअल रूप से अलग करना होगा।
थॉमस ईडिंग

2
इनहेरिटेंस के क्रम को बदलने से समस्या भी ठीक Bangहो Bar, Fooजाएगी - लेकिन आपकी बात एक अच्छी है, +1।
सीन विएरा

1
@ThomasEding आप मैन्युअल रूप से अभी भी भंग कर सकते हैं Bar.zeta(self):।
टायलर क्रॉम्पटन

9

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

मैं यह अमरूद में करता हूं , एक ऐसी भाषा जिस पर मैं काम कर रहा हूं। अमरूद की एक विशेषता यह है कि हम एक विशिष्ट सुपरटाइप के एक तरीके के कार्यान्वयन को लागू कर सकते हैं। तो यह इंगित करना आसान है कि किसी विशेष सिंटैक्स के बिना कौन सा सुपरपेप कार्यान्वयन "विरासत में" होना चाहिए:

type Sequence[+A] {
  String toString() {
    return "[" + ... + "]";
  }
}

type Set[+A] {
  String toString() {
    return "{" + ... + "}";
  }
}

type OrderedSet[+A] extends Sequence[A], Set[A] {
  String toString() {
    // This is Guava's syntax for statically invoking instance methods
    return Set.toString(this);
  }
}

हम हार नहीं मानी, तो OrderedSetअपने आप ही toString, हम एक संकलन त्रुटि मिलेगा। कोई आश्चर्य नहीं।

मुझे एमआई संग्रह के साथ विशेष रूप से उपयोगी लगता है। उदाहरण के लिए, मैं सरणियों, देवताओं, और इसके लिए RandomlyEnumerableSequenceघोषणा करने से बचने के लिए एक प्रकार का उपयोग करना पसंद करता हूं getEnumerator:

type Enumerable[+A] {
  Source[A] getEnumerator();
}

type Sequence[+A] extends Enumerable[A] {
  A get(Int index);
}

type RandomlyEnumerableSequence[+A] extends Sequence[A] {
  Source[A] getEnumerator() {
    ...
  }
}

type DynamicArray[A] extends MutableStack[A],
                             RandomlyEnumerableSequence[A] {
  // No need to define getEnumerator.
}

यदि हमारे पास MI नहीं है, तो हम RandomAccessEnumeratorउपयोग करने के लिए कई संग्रह के लिए लिख सकते हैं, लेकिन एक संक्षिप्त getEnumeratorविधि लिखने के बाद भी बॉयलरप्लेट जोड़ता है।

इसी तरह, एमआई मानक कार्यान्वयन के लिए equals, hashCodeऔर toStringसंग्रह के लिए उपयोगी है ।


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

1
@Asmageddon सहमत हुए, मेरे उदाहरणों में केवल कार्यक्षमता शामिल है। आप मिक्सी के फायदे के रूप में क्या देखते हैं? कम से कम स्काला में, लक्षण अनिवार्य रूप से सिर्फ अमूर्त वर्ग हैं जो एमआई की अनुमति देते हैं - वे अभी भी पहचान के लिए उपयोग किए जा सकते हैं और अभी भी हीरे की समस्या के बारे में ला सकते हैं। क्या अन्य भाषाएँ हैं जहाँ मिक्सिन्स में अधिक दिलचस्प अंतर हैं?
डैनियल लुबरोव

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

2
तुम क्यों कहते हैं Ordered extends Set and Sequenceएक Diamond? यह सिर्फ एक Join है। इसमें hatवर्टेक्स का अभाव है । आप इसे हीरा क्यों कहते हैं? मैंने यहाँ पूछा लेकिन यह एक वर्जित प्रश्न लगता है। आपको कैसे पता चला कि आपको इस त्रिकोणीय संरचना को Join करने के बजाय Diamond कहना होगा?
Val

1
@RecognizeEvilasWaste कि भाषा में एक निहित Topप्रकार है जो घोषित करता है toString, इसलिए वास्तव में एक हीरे की संरचना थी। लेकिन मुझे लगता है कि आपके पास एक बिंदु है - हीरे की संरचना के बिना एक "जॉइन" एक समान समस्या पैदा करता है, और अधिकांश भाषाएं दोनों मामलों को एक ही तरह से संभालती हैं।
डैनियल लुबरोव

7

कई या अन्यथा, विरासत, यह महत्वपूर्ण नहीं है। यदि अलग-अलग प्रकार की दो वस्तुएं प्रतिस्थापन योग्य हैं, तो यह वही है जो विरासत से जुड़ा नहीं होने पर भी मायने रखता है।

एक लिंक की गई सूची और एक चरित्र स्ट्रिंग में सामान्य रूप से बहुत कम है, और इनहेरिटेंस द्वारा लिंक किए जाने की आवश्यकता नहीं है, लेकिन यह उपयोगी है अगर मैं lengthकिसी एक में तत्वों की संख्या प्राप्त करने के लिए फ़ंक्शन का उपयोग कर सकता हूं ।

संहिता के बार-बार कार्यान्वयन से बचने के लिए विरासत एक चाल है। यदि वंशानुक्रम आपको काम बचाता है, और एकाधिक वंशानुक्रम आपको एकल वंशानुक्रम की तुलना में और भी अधिक कार्य बचाता है, तो यह वह सब औचित्य है जिसकी आवश्यकता है।

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

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

बुरी तरह से लागू, असुविधाजनक कुछ भी (जैसे कई विरासत) से नफरत की जानी चाहिए।


2
सूची और स्ट्रिंग कंटेनरों की लंबाई () विधि के साथ आपका उदाहरण खराब है, क्योंकि ये दोनों पूरी तरह से अलग-अलग काम कर रहे हैं। विरासत का उद्देश्य कोड पुनरावृत्ति को कम करना नहीं है। यदि आप कोड पुनरावृत्ति को कम करना चाहते हैं, तो आप सामान्य भागों को एक नई कक्षा में रिफ्लेक्टर करते हैं।
B:07овиЈ

1
@ B @овиЈ दो अलग-अलग चीजों को "पूरी तरह से" नहीं कर रहे हैं।
काज

1
Comparting स्ट्रिंग और सूची , एक पुनरावृत्ति के बहुत सारे देख सकते हैं। इन सामान्य तरीकों को लागू करने के लिए विरासत का उपयोग करना गलत होगा।
B17ови।

1
@ B @овиЈ यह उत्तर में नहीं कहा गया है कि एक स्ट्रिंग और सूची को वंशानुक्रम से जोड़ा जाना चाहिए; काफी विपरीत। किसी सूची या स्ट्रिंग को किसी lengthऑपरेशन में स्थान देने में सक्षम होने का व्यवहार स्वतंत्र रूप से विरासत की अवधारणा से उपयोगी है (जो इस मामले में मदद नहीं करता है: हम कार्यान्वयन को साझा करने की कोशिश करके कुछ भी हासिल करने में सक्षम नहीं हैं। lengthसमारोह के दो तरीके )। फिर भी कुछ अमूर्त विरासत हो सकती है: उदाहरण के लिए सूची और स्ट्रिंग दोनों प्रकार के अनुक्रम हैं (लेकिन जो कोई कार्यान्वयन प्रदान नहीं करता है)।
काज

2
इसके अलावा, वंशानुक्रम एक सामान्य वर्ग के लिए भागों को फिर से भरने का एक तरीका है: आधार वर्ग।
काज

1

जहाँ तक मैं बता सकता हूँ, समस्या का हिस्सा (आपके डिजाइन को समझने के लिए थोड़ा कठिन बनाने के अलावा (फिर भी कोड करना आसान है)) यह है कि कंपाइलर आपके वर्ग डेटा के लिए पर्याप्त स्थान बचाने जा रहा है, जिससे यह एक बड़ी राशि की अनुमति देता है निम्नलिखित मामले में स्मृति अपशिष्ट:

(मेरा उदाहरण सबसे अच्छा नहीं हो सकता है, लेकिन एक ही उद्देश्य के लिए कई मेमोरी स्पेस के बारे में जानने की कोशिश करें, यह पहली बात थी जो मेरे दिमाग में आई: पी)

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

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

मुझे विश्वास है कि इस विचार को लागू करने वाले लोग इस सब के बारे में वास्तव में कठिन हैं, लेकिन मुझे खुशी है कि आपने पूछा, आपका दयालु वह है जो प्रतिमान बदलता है;), और इस पर सहमति जताते हुए, मैं यह नहीं कह रहा हूं कि यह असंभव है (लेकिन कई asumations और एक बहुपरत संकलक को लागू किया जाना चाहिए, और वास्तव में एक जटिल), मैं सिर्फ यह कह रहा हूं कि यह अभी तक मौजूद नहीं है, यदि आप अपने स्वयं के संकलक के लिए एक परियोजना शुरू करते हैं जो "यह" करने में सक्षम है (एकाधिक विरासत) कृपया मुझे बताएं, मैं आपकी टीम में शामिल होने में खुशी होगी।


1
किस बिंदु पर एक संकलक कभी भी यह मान सकता है कि विभिन्न मूल वर्गों से एक ही नाम के चर संयोजन के लिए सुरक्षित हैं? आपको क्या गारंटी है कि caninus.diet और pet.diet वास्तव में एक ही उद्देश्य पूरा करते हैं? आप समान नाम वाले फ़ंक्शन / विधियों के साथ क्या करेंगे?
मि। मिंडोर १४'१३

हाहा, मैं आपसे पूरी तरह सहमत हूँ @ Mr.Mindor, ठीक यही बात मैं अपने उत्तर में कह रहा हूँ, एक ही रास्ता है जो मेरे दिमाग में आता है कि aproach के पास निकटवर्ती प्रोग्रामिंग है, लेकिन मैं यह नहीं कह रहा हूँ कि यह असंभव है , और कहा कि वास्तव में कारण नहीं है क्यों कि मैंने कहा है कि यह है कि कई asumptions संकलन समय के दौरान किया जाना चाहिए, और कुछ अतिरिक्त "डाटा" / especifications तेह प्रोग्रामर द्वारा लिखा होना चाहिए (फिर भी इसे और अधिक कोडिंग, जो मूल समस्या थी है)
Ordiel

-1

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

जब आप अकेले काम कर रहे होते हैं या ज्यादातर कोड पर अलग-थलग हो जाते हैं, तो आपने लिखा है कि यह भारत में 40 लोगों के कोडबेस को विरासत में लेने से पूरी तरह से अलग समस्या है, जिन्होंने बिना किसी संक्रमणकालीन मदद के इसे आपको सौंपने से पहले एक साल तक काम किया।

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

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

आपके कोड में प्रत्येक अंतर्संबंध को टुकड़ों को स्वतंत्र रूप से समझना और संशोधित करना और भी अधिक कठिन हो जाता है, ऐसा कई विरासतों के साथ दोगुना होता है।

जब आप एक टीम के हिस्से के रूप में काम कर रहे होते हैं, तो आप सबसे सरल संभव कोड को लक्षित करना चाहते हैं जो आपको बिल्कुल बेमानी तर्क देता है (यह वास्तव में DRY का अर्थ है, यह नहीं कि आप इतना टाइप न करें कि आपको अपना कोड कभी भी 2 में बदलना न पड़े एक समस्या को हल करने के लिए स्थानों! '

मल्टिपल इनहेरिटेंस की तुलना में DRY कोड प्राप्त करने के सरल तरीके हैं, इसलिए इसमें एक भाषा भी शामिल है जो आपको दूसरों द्वारा डाली गई समस्याओं के लिए खोल सकती है जो आपके समझ के समान स्तर पर नहीं हो सकती हैं। यदि आपकी भाषा आपको अपना कोड DRY रखने का सरल / कम जटिल तरीका पेश करने में असमर्थ है, तो भी यह केवल लुभावना है।


इसके अलावा कल्पना कीजिए कि सलाहकार के बारे में सीख रहे थे - मैंने बहुत सारी गैर-एमआई भाषाएँ (जैसे .net) देखी हैं, जहां सलाहकार इंटरफ़ेस-आधारित DI और IoC के साथ पागल हो गए थे ताकि पूरी चीज़ को अभेद्य रूप से गड़बड़ कर दिया जाए। एमआई इसे बदतर नहीं बनाता है, शायद इसे बेहतर बनाता है।
gbjbaanb

@gbjbaanb आप सही हैं, किसी ऐसे व्यक्ति के लिए यह आसान है जिसे किसी भी फीचर को गड़बड़ाने के लिए जलाया नहीं गया है - वास्तव में यह एक सुविधा सीखने के लिए लगभग एक आवश्यकता है जिसे आप इसे सबसे अच्छा उपयोग करने के लिए देखने के लिए इसे गड़बड़ करते हैं। मैं उत्सुक हूँ, क्योंकि आप कह रहे हैं कि एमआई फोर्स अधिक DI / IoC नहीं है, जो मैंने नहीं देखा है - मुझे नहीं लगता कि जो सलाहकार कोड आपको सभी गंदे इंटरफेस / DI के साथ मिला होगा बेहतर भी एक पूरे पागल-से-कई विरासत पेड़ है, लेकिन यह एमआई के साथ मेरी अनुभवहीनता हो सकती है। क्या आपके पास एक पेज है जो मैं MI के साथ DI / IoC की जगह पर पढ़ सकता हूं?
बिल K

-3

एकाधिक विरासत के खिलाफ सबसे बड़ा तर्क यह है कि कुछ उपयोगी क्षमताएं प्रदान की जा सकती हैं, और कुछ उपयोगी स्वयंसिद्ध पकड़ सकते हैं, एक ढांचे में जो इसे (*) गंभीर रूप से प्रतिबंधित करता है, लेकिन इस तरह के प्रतिबंधों के बिना प्रदान नहीं किया जा सकता है और / या पकड़ नहीं सकता है। उनमें से:

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

  • एक प्रकार की क्षमता के लिए एक मूल वर्ग से एक सदस्य कार्यान्वयन को प्राप्त करने के लिए व्युत्पन्न प्रकार के बिना इसे फिर से लागू करने की क्षमता

  • किसी भी वस्तु उदाहरण को किसी भी संयोजन या अनुक्रम में सीधे अपने या अपने किसी भी प्रकार, और इस तरह के upcasts और downcasts, को हमेशा किसी भी संयोजन या अनुक्रम में ऊपर-नीचे किया जा सकता है

  • स्वयंसिद्ध है कि यदि एक व्युत्पन्न वर्ग एक बेस-क्लास सदस्य को ओवरराइड और चेन करता है, तो बेस सदस्य को सीधे कोडिंग कोड द्वारा आमंत्रित किया जाएगा, और कहीं और नहीं लगाया जाएगा।

(*) आमतौर पर इस प्रकार की आवश्यकता के द्वारा कि कई विरासतों का समर्थन करने वाले प्रकारों को कक्षाओं के बजाय "इंटरफेस" के रूप में घोषित किया जाता है, और उन इंटरफेस को अनुमति नहीं दी जाती जो सामान्य वर्ग कर सकते हैं।

यदि कोई सामान्यीकृत एकाधिक विरासत की अनुमति देना चाहता है, तो कुछ और रास्ता देना चाहिए। यदि X और Y दोनों B से विरासत में प्राप्त होते हैं, तो वे दोनों एक ही सदस्य M और श्रृंखला को आधार कार्यान्वयन के लिए ओवरराइड करते हैं, और यदि D X और Y से विरासत में मिलता है, लेकिन M को ओवरराइड नहीं करता है, तो एक उदाहरण q टाइप D को देखते हुए, क्या करना चाहिए ( B) q) .M () करते हैं? इस तरह के कलाकारों को त्यागने से स्वयंसिद्ध का उल्लंघन होता है जो कहता है कि किसी भी वस्तु को किसी भी प्रकार के आधार पर उतारा जा सकता है, लेकिन कलाकारों और सदस्य आह्वान के किसी भी संभावित व्यवहार से विधि के अस्तर के बारे में स्वयंसिद्ध का उल्लंघन होगा। एक के लिए आवश्यक है कि वर्गों को केवल उनके आधार पर संकलित आधार वर्ग के विशेष संस्करण के संयोजन में लोड किया जाए, लेकिन यह अक्सर अजीब होता है। रनटाइम के पास किसी भी प्रकार को लोड करने से इंकार करना, जिसमें किसी भी पूर्वज को एक से अधिक मार्गों तक पहुँचा जा सकता है, काम करने योग्य हो सकता है, लेकिन बहुत से वंशानुक्रम की उपयोगिता को सीमित करेगा। साझा विरासत के रास्तों की अनुमति केवल तभी होती है जब कोई संघर्ष मौजूद नहीं होता है, ऐसी परिस्थितियाँ उत्पन्न होती हैं जहाँ X का एक पुराना संस्करण पुराने या नए Y के साथ संगत होगा, और एक पुराना Y एक पुराने या नए X के साथ संगत होगा, लेकिन नया X और नया Y संगत रहें, भले ही न तो ऐसा कुछ भी किया गया हो, जिसमें खुद को और एक को तोड़ने के बदलाव की उम्मीद की जानी चाहिए।

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


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

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

@cHao: यदि किसी को आवश्यकता है कि व्युत्पन्न वर्गों को माता-पिता के तरीकों को ओवरराइड करना चाहिए, न कि उन्हें (इंटरफेस के रूप में एक ही नियम) श्रृंखला से समस्याओं से बचा जा सकता है, लेकिन यह एक बहुत गंभीर सीमा है। एक एक पैटर्न जहां का उपयोग करता है FirstDerivedFoo'का रों ओवरराइड Barएक संरक्षित गैर आभासी करने के लिए लेकिन श्रृंखला कुछ नहीं करता है FirstDerivedFoo_Bar, और SecondDerivedFooकरने के लिए की ओवरराइड चेन संरक्षित गैर आभासी SecondDerivedBar, और कोड बेस विधि में पहुंचना चाहता है कि उन की रक्षा की गैर आभासी तरीकों का उपयोग करता है, उस एक व्यावहारिक दृष्टिकोण हो सकता है ...
सुपरकैट

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

एमआई में कोई अंतर्निहित आवश्यकता नहीं है कि कक्षाएं आधार विधियों को नहीं बुलाती हैं, और किसी विशेष कारण की आवश्यकता नहीं होगी। एमआई को दोष देना थोड़ा अजीब लगता है, इस समस्या को देखते हुए एसआई भी प्रभावित होता है।
cHao
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.