java - विरासत का उपयोग क्यों करें?




oop language-agnostic (9)

मुझे पता है कि इस सवाल पर पहले चर्चा की गई है , लेकिन ऐसा लगता है कि विरासत कम से कम कभी-कभी रचना के लिए बेहतर होती है। मैं कुछ समझ हासिल करने की उम्मीद में उस धारणा को चुनौती देना चाहता हूं।

मेरा सवाल यह है: चूंकि आप ऑब्जेक्ट संरचना के साथ कुछ भी हासिल कर सकते हैं जिसे आप शास्त्रीय विरासत के साथ कर सकते हैं और चूंकि शास्त्रीय विरासत का अक्सर दुर्व्यवहार किया जाता है [1] और चूंकि ऑब्जेक्ट संरचना आपको प्रतिनिधि ऑब्जेक्ट रनटाइम को बदलने के लिए लचीलापन देती है, तो आप कभी भी क्यों उपयोग करेंगे शास्त्रीय विरासत?

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

मेरे प्रश्न को बताने का एक और तरीका यह है: यहां तक ​​कि यदि आप जानते हैं कि शास्त्रीय विरासत किसी निश्चित मॉडल को लागू करने के लिए गलत नहीं है, तो क्या रचना के बजाए इसका उपयोग करने के लिए पर्याप्त कारण है?

[1] कई लोग अपने वर्गों को इंटरफ़ेस को लागू करने की बजाय बहुरूपता प्राप्त करने के लिए शास्त्रीय विरासत का उपयोग करते हैं। विरासत का उद्देश्य कोड पुन: उपयोग है, न कि बहुरूपता। इसके अलावा, कुछ लोग विरासत का उपयोग "एक-ए" रिश्ते की सहज ज्ञान को समझने के लिए करते हैं जो अक्सर समस्याग्रस्त हो सकता है

अद्यतन करें

जब मैं विरासत के बारे में बात करता हूं तो मैं सिर्फ यह स्पष्ट करना चाहता हूं कि मेरा क्या मतलब है:

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

अद्यतन 2

मैं समझता हूं कि विरासत मैं सी ++ polymorphism प्राप्त करने का एकमात्र तरीका है। उस स्थिति में यह स्पष्ट है कि आपको इसका उपयोग क्यों करना चाहिए। तो मेरा प्रश्न जावा या रूबी जैसी भाषाओं तक सीमित है जो क्रमशः पॉलिमॉर्फिज्म (इंटरफेस और बतख टाइपिंग) प्राप्त करने के लिए अलग-अलग तरीकों की पेशकश करते हैं।


विरासत का उद्देश्य कोड पुन: उपयोग है, न कि बहुरूपता।

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

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

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

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


आप ने लिखा:

[1] कई लोग अपने वर्गों को इंटरफ़ेस को लागू करने की बजाय बहुरूपता प्राप्त करने के लिए शास्त्रीय विरासत का उपयोग करते हैं। विरासत का उद्देश्य कोड पुन: उपयोग है, न कि बहुरूपता। इसके अलावा, कुछ लोग विरासत का उपयोग "एक-ए" रिश्ते की सहज ज्ञान को समझने के लिए करते हैं जो अक्सर समस्याग्रस्त हो सकता है।

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

विरासत इंटरफ़ेस पुन: उपयोग के बारे में है , कार्यान्वयन पुन: उपयोग नहीं। जैसा कि आपने उपरोक्त लिखा है, यह कोड पुन: उपयोग के बारे में नहीं है।

विरासत, जैसा कि आप सही ढंग से इंगित करते हैं, एक आईएस-ए रिश्ते को मॉडल करने के लिए है (तथ्य यह है कि बहुत से लोगों को यह गलत लगता है कि प्रतिभागिता से कोई लेना देना नहीं है)। आप 'BEHAVES-LIKE-A' भी कह सकते हैं। हालांकि, सिर्फ इसलिए कि किसी चीज़ के साथ कुछ आईएस-ए संबंध है, इसका मतलब यह नहीं है कि यह इस संबंध को पूरा करने के लिए समान (या यहां तक ​​कि समान) कोड का उपयोग करता है।

इस सी ++ उदाहरण की तुलना करें जो डेटा आउटपुट के विभिन्न तरीकों को लागू करता है; दो वर्ग (सार्वजनिक) विरासत का उपयोग करते हैं ताकि वे बहुरूप रूप से पहुंच सकें:

struct Output {
  virtual bool readyToWrite() const = 0;
  virtual void write(const char *data, size_t len) = 0;
};

struct NetworkOutput : public Output {
  NetworkOutput(const char *host, unsigned short port);

  bool readyToWrite();
  void write(const char *data, size_t len);
};

struct FileOutput : public Output {
  FileOutput(const char *fileName);

  bool readyToWrite();
  void write(const char *data, size_t len);
};

अब कल्पना करें कि यह जावा था। 'आउटपुट' कोई संरचना नहीं थी, लेकिन एक 'इंटरफ़ेस' था। इसे 'लिखने योग्य' कहा जा सकता है। 'सार्वजनिक आउटपुट' के बजाय आप 'लिखने योग्य' कहेंगे। जहां तक ​​डिजाइन का संबंध है, इसमें क्या अंतर है?

कोई नहीं।


जब आपने पूछा:

यहां तक ​​कि यदि आप जानते हैं कि शास्त्रीय विरासत किसी निश्चित मॉडल को लागू करने के लिए गलत नहीं है, तो क्या रचना के बजाए इसका उपयोग करने के लिए पर्याप्त कारण है?

जवाब न है। यदि मॉडल गलत है (विरासत का उपयोग करके), इससे कोई फर्क नहीं पड़ता कि इससे कोई फर्क नहीं पड़ता।

यहां विरासत के साथ कुछ समस्याएं हैं जिन्हें मैंने देखा है:

  1. हमेशा व्युत्पन्न क्लास पॉइंटर्स के रन टाइम प्रकार का परीक्षण करने के लिए यह देखने के लिए कि क्या उन्हें कास्ट किया जा सकता है (या नीचे भी)।
  2. यह 'परीक्षण' विभिन्न तरीकों से हासिल किया जा सकता है। आपके पास कुछ प्रकार की वर्चुअल विधि हो सकती है जो क्लास पहचानकर्ता लौटाती है। या विफल रहा है कि आपको आरटीटीआई (रन टाइम टाइप पहचान) को लागू करना पड़ सकता है (कम से कम सी / सी ++ में) जो आपको एक प्रदर्शन हिट दे सकता है।
  3. वर्ग प्रकार जो 'कास्ट' पाने में विफल रहते हैं, संभावित रूप से समस्याग्रस्त हो सकते हैं।
  4. विरासत के पेड़ को ऊपर और नीचे अपने वर्ग के प्रकार को कास्ट करने के कई तरीके हैं।

टेम्पलेट विधि पैटर्न के बारे में क्या? आइए मान लें कि आपके पास अनुकूलन नीतियों के लिए बहुत से अंक हैं, लेकिन एक रणनीति पैटर्न निम्नलिखित कारणों में से कम से कम एक के लिए समझ में नहीं आता है:

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

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


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


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

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


विरासत का उपयोग करने के लिए देखे जाने वाले सबसे उपयोगी तरीकों में से एक जीयूआई वस्तुओं में है।


विरासत को प्राथमिकता दी जानी चाहिए यदि:

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

मेरा निष्कर्ष: प्रतिनिधिमंडल प्रोग्रामिंग भाषा में एक बग के लिए एक कामकाज है।


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





composition