"वंशानुक्रम पर रचना को प्राथमिकता दें" - क्या हस्ताक्षर परिवर्तन के खिलाफ बचाव का एकमात्र कारण है?


13

यह पृष्ठ निम्नलिखित तर्क के साथ वंशानुक्रम पर रचना की वकालत करता है (मेरे शब्दों में इसे कहा गया है):

सुपरक्लास की एक विधि के हस्ताक्षर में बदलाव (जो उपवर्ग में ओवरराइड नहीं किया गया है) जब हम इनहेरिटेंस का उपयोग करते हैं, तो कई स्थानों पर अतिरिक्त परिवर्तन होता है। हालाँकि, जब हम संरचना का उपयोग करते हैं, तो आवश्यक अतिरिक्त परिवर्तन केवल एक ही स्थान पर होता है: उपवर्ग।

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




2
उद्धरण यह नहीं कहता कि यह "एकमात्र" कारण है।
ट्यूलेंस कोरडोवा

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

जवाबों:


27

मुझे यहाँ की एनालॉगियाँ पसंद हैं: क्या आपने कभी उन टीवी में से एक को देखा है जिनके पास वीसीआर प्लेयर बिल्ट-इन था? कैसे एक के बारे में एक वीसीआर और एक डीवीडी प्लेयर के साथ? या एक जिसमें ब्लू-रे, डीवीडी और वीसीआर है। ओह और अब हर कोई स्ट्रीमिंग कर रहा है इसलिए हमें एक नया टीवी सेट डिजाइन करने की आवश्यकता है ...

सबसे अधिक संभावना है, यदि आप एक टीवी सेट के मालिक हैं, तो आपके पास ऊपर जैसा नहीं है। संभवतः उनमें से अधिकांश कभी अस्तित्व में भी नहीं थे। आपके पास संभवतः एक मॉनिटर या सेट है जिसमें कई इनपुट हैं ताकि आपको हर बार एक नए सेट की आवश्यकता न हो एक नया प्रकार का इनपुट डिवाइस है।

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


6
90 के दशक के अंत और 2000 की शुरुआत में वीसीआर और डीवीडी प्लेयर के साथ बहुत सारे टीवी थे।
JAB

@ जेएबी और कई (सबसे?) टीवी आज स्ट्रीमिंग का समर्थन करते हैं, इस मामले के लिए।
केसी

4
@ जेएबी और उनमें से कोई भी अपने डीवीडी प्लेयर को एक ब्लायेर खिलाड़ी को खरीदने में मदद करने के लिए नहीं बेच सकता है
अलेक्जेंडर - मोनिक

1
@ जाब सही। बयान "क्या आपने कभी उन टीवी में से एक को देखा है जिनके पास वीसीआर प्लेयर बिल्ट-इन था?" तात्पर्य वे मौजूद हैं।
जिमीजैम

4
@ कैसी क्योंकि जाहिर है, एक और तकनीक नहीं होगी जो इस एक को सुपरसाइड करेगी, है ना? मैं दांव लगाऊंगा कि उनमें से कोई भी टीवी बाहरी उपकरणों से इनपुट का समर्थन करता है, अगर कोई नया टीवी खरीदने के बिना किसी और का उपयोग करना चाहता है। या यों कहें कि कुछ शिक्षित खरीदार ऐसे इनपुट की कमी वाले टीवी को खरीदने के इच्छुक हैं। मेरा आधार यह नहीं है कि ये दृष्टिकोण मौजूद नहीं हैं और न ही मैं यह दावा करूंगा कि विरासत मौजूद नहीं है। मुद्दा यह है कि ऐसे दृष्टिकोण रचना की तुलना में स्वाभाविक रूप से कम लचीले होते हैं।
जिमीजैम

4

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

इस तरह, आपके पास कुछ ऑब्जेक्ट हैं जो सर्विसियक प्रदान करते हैं। अन्य व्यवहार को सक्षम करने के लिए आप उन्हें बिल्डिंग ब्लॉक्स के रूप में उपयोग करते हैं (लेगो की तरह बहुत सुंदर) (जैसे एक UserRegistrationService एक ईमेल सेवा और एक UserRepository द्वारा प्रदान की गई सेवाओं का उपयोग करता है )।

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


मुझे यहां जावा मानसिकता दिखाई देती है। OOP उस डेटा के साथ मिलकर काम करता है जो उस पर कार्य करता है - जो आप बता रहे हैं उसे "मॉड्यूल" कहा जाता है। आप सही हैं कि विरासत से बचना एक अच्छा विचार है जब आप ऑब्जेक्ट्स को मॉड्यूल के रूप में पुन: प्रस्तुत कर रहे हैं, लेकिन मुझे यह परेशान करने वाला लगता है कि आप अनुशंसा कर रहे हैं कि ऑब्जेक्ट का उपयोग करने का पसंदीदा तरीका है।
ब्रिलियनड

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

@Tsar दुर्भाग्य से, भले ही जावा स्थिर तरीकों का समर्थन करता है, जावा संस्कृति नहीं करता है
k_g

@ ब्रिलियन कौन "OOP" के बारे में परवाह करता है? क्या मायने रखता है कि आप इसे कैसे उपयोग कर सकते हैं और उन तरीकों से इसका उपयोग कर सकते हैं।
user253751

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

4

"वंशानुक्रम पर पसंदीदा रचना" सिर्फ एक अच्छा अनुमान है

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

मैं इस पोस्ट के साथ इस बिंदु को स्पष्ट करने की उम्मीद करता हूं।

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


वाहन का उदाहरण

मैं उन डेवलपर्स के बारे में लिख रहा हूं जो कथा उद्देश्यों के लिए गूंगे तरीके से चीजों की कोशिश करते हैं

कि कुछ OOP पाठ्यक्रम का उपयोग हमें शास्त्रीय उदाहरण का एक संस्करण के लिए चलते हैं ... हम एक है Vehicle, वर्ग तो हम निकाले जाते हैं Car, Airplane, Balloonऔर Ship

नोट : यदि आपको इस उदाहरण को आधार बनाने की आवश्यकता है, तो दिखावा करें कि ये वीडियो गेम में वस्तुओं के प्रकार हैं।

तब Carऔर Airplaneकुछ सामान्य कोड हो सकते हैं, क्योंकि वे दोनों जमीन पर पहिया पर रोल कर सकते हैं। डेवलपर्स इसके लिए वंशानुक्रम श्रृंखला में एक मध्यस्थ वर्ग बनाने पर विचार कर सकते हैं। फिर भी, वास्तव में Airplaneऔर के बीच कुछ साझा कोड भी है Balloon। वे इसके लिए विरासत श्रृंखला में एक और मध्यस्थ वर्ग बनाने पर विचार कर सकते हैं।

इस प्रकार, डेवलपर कई उत्तराधिकार की तलाश में होगा। उस बिंदु पर जहां डेवलपर्स कई विरासत की तलाश कर रहे हैं, डिजाइन पहले ही गलत हो गया है।

इस व्यवहार को इंटरफेस और रचना के रूप में मॉडल करना बेहतर है, इसलिए हम इसे कई वर्ग उत्तराधिकार में चलाने के बिना पुन: उपयोग कर सकते हैं। यदि डेवलपर्स, उदाहरण के लिए, FlyingVehiculeवर्ग बनाते हैं । वे कह रहे हैं कि Airplaneयह एक FlyingVehicule(श्रेणी विरासत) है, लेकिन हम इसके बजाय यह कह सकते हैं कि Airplaneएक Flyingघटक (रचना) है और Airplaneएक IFlyingVehicule(इंटरफ़ेस विरासत) है।

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

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

बिना जिक्र किए सब Amphibious

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


सबस्टिबिलिटी और एनकैप्सुलेशन

Aवंशानुक्रम या रचना करनी चाहिए B?

यदि उस Aकी एक विशेषज्ञता Liskov प्रतिस्थापन सिद्धांतB को पूरा करना चाहिए , तो वंशानुक्रम व्यवहार्य है, यहां तक ​​कि वांछनीय भी है। यदि ऐसी परिस्थितियां हैं, जिनके लिए एक वैध प्रतिस्थापन नहीं है, तो हमें विरासत का उपयोग नहीं करना चाहिए।AB

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

हम भी तर्क दे सकता है कि देखते हैं अगर में सुविधाओं Bहै कि Aजरूरत नहीं है (और अगर उन सुविधाओं के लिए एक अमान्य स्थिति में हो सकता है हम नहीं जानते A, या तो वर्तमान कार्यान्वयन में या भविष्य में), यह उपयोग संरचना के लिए एक अच्छा विचार है विरासत के बदले।

कंपोज़िशन में स्विचिंग इंप्लीमेंटेशन की अनुमति देने और मॉकिंग को आसान बनाने के फायदे भी हैं।

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

अंत में, निश्चित रूप से, यह तर्क है कि हमें मूल वर्ग का बचाव करने के लिए रचना का उपयोग करना चाहिए क्योंकि वंशानुक्रम मूल वर्ग के इनकैप्सुलेशन को तोड़ता है:

वंशानुक्रम अपने माता-पिता के कार्यान्वयन के विवरण के लिए एक उपवर्ग को उजागर करता है, यह अक्सर कहा जाता है कि 'वंशानुक्रम विच्छेद को तोड़ता है'

- डिजाइन पैटर्न: पुन: प्रयोज्य वस्तु-उन्मुख सॉफ्टवेयर के तत्व, गैंग ऑफ़ फोर

ठीक है, यह एक खराब डिजाइन वाला मूल वर्ग है। यही कारण है कि तुम चाहिए:

वंशानुक्रम के लिए डिज़ाइन करें, या इसे प्रतिबंधित करें।

- प्रभावी जावा, जोश बलोच


यो-यो समस्या

एक और मामला जहां रचना मदद करती है वह है यो-यो समस्या । यह विकिपीडिया का एक उद्धरण है:

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

आप उदाहरण के लिए हल कर सकते हैं: आपकी कक्षा कक्षा Cसे विरासत में नहीं आएगी B। इसके बजाय आपकी कक्षा Cमें एक प्रकार का सदस्य होगा A, जो किसी प्रकार की वस्तु हो सकती है (या हो सकती है) B। इस तरह से आप कार्यान्वयन विवरण के विरुद्ध प्रोग्रामिंग नहीं करेंगे B, लेकिन उस अनुबंध के विरुद्ध जो इंटरफ़ेस () का Aप्रस्ताव देता है।


काउंटर उदाहरण

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

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

परिशिष्ट : कुछ अन्य तरीके हैं जो ओआरएम वस्तुओं का विस्तार कर सकते हैं। इस प्रकार, मुझे नहीं लगता कि इस मामले में विरासत जरूरी है। यह सस्ता है।

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

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

इसके अलावा, विचार करें कि कई बार हम केवल कुछ तरीकों को ओवरराइड करना चाहते हैं और डिफ़ॉल्ट कार्यान्वयन के साथ बाकी सब कुछ छोड़ देते हैं। यदि हम रचना का उपयोग कर रहे थे तो हमें उन सभी तरीकों को बनाना होगा, भले ही केवल लपेटी गई वस्तु को सौंपना हो।

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

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


अंतिम विचार

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

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

मेरे पास एक हालिया पोस्ट है जहां मैं इंटरफेस के कुछ फायदों के बारे में बात करता हूं कि हमें सी # में यूआई, बिजनेस और डेटा एक्सेस के बीच इंटरफेस की आवश्यकता क्यों है । यह decoupling में मदद करता है और पुन: प्रयोज्यता और परीक्षणशीलता को आसान बनाता है, आपको रुचि हो सकती है।


उह… .नेट फ्रेमवर्क धारा-संबंधी कार्य करने के लिए कई प्रकार की विरासत में मिली धाराओं का उपयोग करता है। यह अविश्वसनीय रूप से अच्छी तरह से काम करता है और इसका उपयोग करना और विस्तार करना आसान है। आपका उदाहरण बहुत अच्छा नहीं है ...
टी। सारा

1
@TSar "का उपयोग करना और विस्तार करना सुपर आसान है" क्या आपने कभी डिबग के लिए मानक आउट स्ट्रीम को टी करने की कोशिश की है? यह मेरा एकमात्र अनुभव रहा है कि मैं उनकी धाराओं का विस्तार करूं। यह आसान नहीं था। यह एक बुरा सपना था जो स्पष्ट रूप से कक्षा में हर एक विधि को ओवरराइड करने के बाद समाप्त हो गया। अत्यंत दोहराव। और यदि आप .NET स्रोत कोड को देखते हैं, तो सब कुछ स्पष्ट रूप से ओवरराइड करना बहुत अधिक है कि वे इसे कैसे करते हैं। इसलिए मुझे यकीन नहीं है कि यह कभी भी आसान है।
jpmc26

एक स्ट्रीम से एक संरचना पढ़ना और लिखना नि: शुल्क कार्यों, या मल्टीमिथोड्स के साथ बेहतर किया जाता है।
user253751

@ jpmc26 मुझे खेद है कि आपका अनुभव बहुत अच्छा नहीं था। हालांकि, अलग-अलग चीजों के लिए स्ट्रीम-संबंधित सामान का उपयोग या कार्यान्वित करने में मेरे पास कोई समस्या नहीं थी।
टी। सर

3

आम तौर पर रचना-ओवर-इनहेरिटेंस का ड्राइविंग विचार अधिक से अधिक डिज़ाइन लचीलापन प्रदान करना है और कोड की मात्रा को कम करने के लिए नहीं है जो आपको बदलने के लिए बदलने की आवश्यकता है (जो मुझे संदेहास्पद लगता है)।

विकिपीडिया पर उदाहरण उनके दृष्टिकोण की शक्ति का एक बेहतर उदाहरण देता है:

प्रत्येक "कंपोज़िशन-पीस" के लिए एक बेस इंटरफ़ेस को परिभाषित करना आप विभिन्न "कंपोज़्ड-ऑब्जेक्ट" को एक ऐसी विविधता के साथ बना सकते हैं जो अकेले विरासत के साथ पहुंचना मुश्किल हो सकता है।


तो यह खंड एक उदाहरण उदाहरण देता है, है ना? मैं पूछ रहा हूं क्योंकि यह लेख में स्पष्ट नहीं है।
उत्कर्ष

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

2

लाइन: "विरासत के ऊपर रचना को प्राथमिकता दें" सही दिशा में एक कुहनी के सिवा कुछ नहीं है। यह आपको अपनी मूर्खता से बचाने वाला नहीं है और वास्तव में आपको चीजों को बहुत खराब करने का मौका देता है। ऐसा इसलिए क्योंकि यहां बहुत शक्ति है।

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

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

अगले दिन मैं पूछता हूं कि क्या यही था। आपको क्या लगता है कि बॉस क्या कहता है?

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

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

रचना और प्रतिनिधिमंडल (और कुछ नुकसान) के साथ विरासत को स्वचालित रूप से प्रतिस्थापित करने के कुछ मामूली फायदे हैं लेकिन इस प्रक्रिया के दौरान आपके मस्तिष्क को बंद रखने से एक बड़ा अवसर गायब है।

अप्रत्यक्ष बहुत शक्तिशाली है। समझदारी से इस्तेमाल करो।


0

यहाँ एक और कारण है: कई OO भाषाओं में (मैं यहाँ C ++, C # या Java जैसे लोगों के बारे में सोच रहा हूँ), आपके द्वारा एक बार बनाने के बाद किसी वस्तु के वर्ग को बदलने का कोई तरीका नहीं है।

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

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

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

यह एक ठोस कर्मचारी वर्ग बनाने के लिए जीवन को इतना आसान बनाता है, और इसे एक कंटेनर के रूप में मानता है जिसमें आप गुणों को जोड़ सकते हैं, जैसे कि नौकरी की भूमिका।


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

0

वंशानुक्रम दो चीजें प्रदान करता है:

1) कोड-पुन: उपयोग: रचना के माध्यम से आसानी से पूरा किया जा सकता है। और वास्तव में, रचना के माध्यम से बेहतर हासिल किया जाता है क्योंकि यह बेहतर रूप से एनकैप्सुलेशन को संरक्षित करता है।

2) बहुरूपता: "इंटरफेस" (कक्षाओं जहां सभी तरीके शुद्ध-आभासी हैं) के माध्यम से पूरा किया जा सकता है।

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

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

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


0

क्या यह वास्तव में विरासत पर रचना का पक्ष लेने का एकमात्र कारण है?

नहीं।

वंशानुक्रम पर रचना का पक्ष लेने के कई कारण हैं। एक भी सही उत्तर नहीं है। लेकिन मैं मिश्रण में विरासत से अधिक रचना के पक्ष में एक और कारण फेंकूंगा:

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

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

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

यहां एक ठोस उदाहरण दिया गया है: जावा में JFrameवर्ग एक खिड़की का प्रतिनिधित्व करता है। एक विंडो बनाने के लिए, आप एक इंस्टेंस बनाते हैं JFrameऔर फिर उस इंस्टेंस पर कॉल करके उसमें सामान जोड़ते हैं और उसे दिखाते हैं।

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

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

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


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

1
@ jpmc26 ... पृथ्वी पर आपको एक वर्ग का एक नया उदाहरण बनाने के लिए सिर्फ एक कारखाना वर्ग की आवश्यकता क्यों होगी? और आप जो वर्णन कर रहे हैं, उसकी पठनीयता में कैसे सुधार होता है?
केविन कर्मकार

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

जैसा कि मैंने कहा, इसका मतलब यह नहीं है कि विरासत अच्छी है, लेकिन यह इस बात की मिसाल देता है कि कुछ स्थितियों में रचना पठनीयता में कैसे सुधार नहीं करती है।
jpmc26

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