बहुरूपता के संदर्भ में उपप्रकारों के लिए जोड़े गए तरीकों को कैसे संभालना है?


14

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

आपके पास जानवरों का संग्रह है और आप सभी जानवरों के कार्यों को बुलाते हैं eatऔर आपको यह ध्यान नहीं है कि यह एक कुत्ता खाने वाला या बिल्ली है। लेकिन एक ही श्रेणी के पदानुक्रम में आपके पास ऐसे जानवर हैं जिनके पास अतिरिक्त है - वर्ग से विरासत में मिला और लागू किया गया Animal, जैसे makeEggs, getBackFromTheFreezedStateऔर इसी तरह। तो कुछ मामलों में आप कार्य करते हैं आप अतिरिक्त व्यवहार को कॉल करने के लिए विशिष्ट प्रकार जानना चाह सकते हैं।

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


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

24
यदि आप एक Eaterइंटरफ़ेस को eat()विधि के साथ परिभाषित करते हैं , तो एक ग्राहक के रूप में, आपको परवाह नहीं है कि Humanइसे लागू करने के लिए पहले कॉल करना होगा washHands()और getDressed(), यह इस वर्ग का कार्यान्वयन विवरण है। यदि, एक ग्राहक के रूप में, आप इस तथ्य की परवाह करते हैं, तो आप सबसे अधिक संभावना है कि आप नौकरी के लिए सही उपकरण का उपयोग नहीं करेंगे।
विंसेंट सवार्ड

3
आपको यह भी विचार करना होगा कि सुबह के समय, एक मानव को getDressedउनसे पहले की आवश्यकता हो सकती है eat, दोपहर के भोजन के लिए ऐसा नहीं है। आपकी परिस्थितियों के आधार पर, washHands();if !dressed then getDressed();[code to actually eat]मानव के लिए इसे लागू करने का सबसे अच्छा तरीका हो सकता है। एक अन्य संभावना यह है कि यदि अन्य चीजों की आवश्यकता होती है washHandsऔर / या getDressedकहा जाता है? मान लो तुम्हारे पास है leaveForWork? आपको अपने प्रोग्राम के फ्लो को स्ट्रक्चर करने की आवश्यकता हो सकती है जैसे कि यह वैसे भी बहुत पहले कहा जाता है।
डंकन एक्स सिम्पसन

1
ध्यान रखें कि सटीक प्रकार के खिलाफ जाँच OOP में एक कोड गंध हो सकती है लेकिन यह FP (यानी एक भेदभाव वाले संघ के प्रकार को निर्धारित करने के लिए मिलान पैटर्न का उपयोग करें और फिर उस पर कार्य करें) में एक बहुत ही सामान्य अभ्यास है।
थियोडोरोस चटजिआनकिंस

3
जानवरों की तरह OO पदानुक्रम के स्कूल के कमरे के उदाहरण। वास्तविक कार्यक्रमों में लगभग कभी भी ऐसी स्वच्छ कर व्यवस्था नहीं होती है। जैसे, ericlippert.com/2015/04/27/wizards-and-warriors-part-one । या अगर आप पूरे हॉग जाना चाहते हैं और पूरे प्रतिमान पर सवाल उठाते हैं: ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग बैड है
jpmc26

जवाबों:


18

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

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

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

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


33

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

पहले, मैं स्पष्ट हो जाऊं। यह आपकी गलती नहीं है। आमतौर पर OO को जिस तरह से पढ़ाया जाता है वह अत्यधिक त्रुटिपूर्ण है। इसका Animalउदाहरण प्रीमियर अपराधी, IMO है। मूल रूप से, हम कहते हैं, चलो वस्तुओं के बारे में बात करते हैं, वे क्या कर सकते हैं। एक Animalकर सकते हैं eat()और यह कर सकते हैं speak()। उत्तम। अब कुछ जानवरों और कोड बनाएं कि वे कैसे खाते हैं और बोलते हैं। अब आप जानते हैं कि ओ ओ, सही है?

समस्या यह है कि यह गलत दिशा से ओओ पर आ रहा है। इस कार्यक्रम में जानवर क्यों हैं और उन्हें बोलने और खाने की आवश्यकता क्यों है?

मेरे पास एक Animalप्रकार के लिए एक वास्तविक उपयोग के बारे में सोचने का कठिन समय है । मुझे यकीन है कि यह मौजूद है लेकिन आइए एक ऐसी चीज़ के बारे में चर्चा करें जो मुझे लगता है कि इस कारण से आसान है: एक ट्रैफ़िक सिमुलेशन। मान लें कि हम विभिन्न परिदृश्यों में ट्रैफ़िक को मॉडल करना चाहते हैं। यहाँ कुछ बुनियादी चीजें हैं जो हमें करने में सक्षम होना चाहिए।

Vehicle
Road
Signal

हम पैदल और रेलगाड़ियों के सभी प्रकार के साथ गहराई तक जा सकते हैं लेकिन हम इसे सरल रखेंगे।

आइए विचार करें Vehicle। वाहन को किन क्षमताओं की आवश्यकता है? इसके लिए सड़क पर सफर करना पड़ता है। इसे संकेतों पर रोकने में सक्षम होने की आवश्यकता है। इसे चौराहों को नेविगेट करने में सक्षम होना चाहिए।

interface Vehicle {
  move(Road road);
  navigate(Road... intersection);
}

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

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

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


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

@VincentSavard "मैं तर्क करूँगा कि यह एकमात्र तरीका है।" तुम सही हो। मुझे लगता है कि इसका कारण यह है कि मैंने इसे पूर्ण नहीं बनाया है, एक बार जब आपको यह विचार आता है, तो आप इंटरफ़ेस को बाहर निकाल सकते हैं और फिर इसे इस तरह से परिष्कृत कर सकते हैं। अंत में, जब आप पीतल के ढेर पर उतरते हैं, तो यह केवल एक चीज होती है जो मायने रखती है।
जिमीजैम

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

9

टी एल; डॉ:

एक अमूर्त और तरीकों के बारे में सोचें जो सभी उपवर्गों पर लागू होते हैं और आपकी ज़रूरत की सभी चीज़ों को कवर करते हैं।

आइए सबसे पहले अपने eat()उदाहरण के साथ बने रहें ।

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

सॉफ्टवेयर पर वापस:

एक के रूप में Humanउदाहरण के पूर्व शर्त के बिना खाने के लिए नहीं होगा, मैं होगा Humanकी eat()विधि करने washHands()और getDressed()है कि अगर ऐसा नहीं किया गया है। eat()उस ख़ासियत के बारे में जानने वाले के रूप में यह आपका काम नहीं होना चाहिए । जिद्दी-मानव का विकल्प एक अपवाद फेंकना होगा ("मैं खाने के लिए तैयार नहीं हूं!") यदि पूर्व शर्त पूरी नहीं हुई, तो आपको निराश होना चाहिए, लेकिन कम से कम सूचित किया कि खाने से काम नहीं चला।

किस बारे में makeEggs()?

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


मैं इस जवाब से सहमत हूं। Narek कोड गंध के बारे में सही है। यह इंटरफ़ेस डिज़ाइन है जो बदबूदार है, इसलिए इसे और अपने अच्छे को ठीक करें।
जोनाथन वैन डे वीन

इस उत्तर का वर्णन आमतौर पर लिस्कोव प्रतिस्थापन सिद्धांत के रूप में किया जाता है ।
फिलीपींस

2

जवाब बहुत सरल है।

उन वस्तुओं को कैसे संभालें जो आपकी अपेक्षा से अधिक कर सकते हैं?

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

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

उदाहरण के लिए, स्यूडोकोड में:

interface IEater { void Eat(); }
interface IMorningRoutinePerformer { void DoMorningRoutine(); }
interface IAnimal : IEater, IMorningPerformer;
interface IHuman : IEater, IMorningPerformer; 
{
  void WashHands();
  void GetDressed();
}

void MorningTime()
{
   IList<IMorningRoutinePerformer> items = Service.GetMorningPerformers();
   foreach(item in items) { item.DoMorningRoutine(); }
}

अब आप को लागू IMorningPerformerकरने के लिए Animalसिर्फ खाने प्रदर्शन करने के लिए, और के लिए Humanआप भी हाथ धोने के लिए और तैयार हो जाओ इसे लागू। अपने मॉर्निंगटाइम विधि का कॉलर कम देखभाल कर सकता है यदि यह मानव या एक जानवर है। सभी यह चाहते हैं कि सुबह की दिनचर्या का प्रदर्शन किया जाए, जो प्रत्येक वस्तु OO को धन्यवाद देती है।

बहुरूपता मर जाता है।

या करता है?

आपको ऑब्जेक्ट के प्रकार का पता लगाने की आवश्यकता है

ऐसा क्यों मान रहे हैं? मुझे लगता है कि यह एक गलत धारणा हो सकती है।

क्या इस मामलों को संभालने के लिए एक आम तरीका है?

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

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

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

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


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