जावा वंशानुक्रम से क्यों बचें "विस्तार"


40

जामे गोसलिंग ने कहा

"जब भी संभव हो आप कार्यान्वयन विरासत से बचना चाहिए।"

और इसके बजाय, इंटरफ़ेस वंशानुक्रम का उपयोग करें।

पर क्यों? हम "एक्सटेंड्स" कीवर्ड का उपयोग करके किसी ऑब्जेक्ट की संरचना को इनहेरिट करने से कैसे बच सकते हैं, और साथ ही साथ हमारे कोड ऑब्जेक्ट ओरिएंटेड बनाते हैं?

क्या कोई व्यक्ति ऑब्जेक्ट ओरिएंटेड उदाहरण दे सकता है जो इस अवधारणा को एक परिदृश्य में दर्शाता है जैसे "एक किताबों की दुकान में एक पुस्तक का आदेश देना?"



समस्या यह है कि आप केवल एक वर्ग का विस्तार कर सकते हैं ।

जवाबों:


38

गोस्लिंग ने फैली हुई कीवर्ड के उपयोग से बचने के लिए नहीं कहा ... उन्होंने कहा कि कोड री-यूज़ को प्राप्त करने के साधन के रूप में उत्तराधिकार का उपयोग न करें।

वंशानुक्रम प्रति खराब नहीं है और OO संरचनाओं को बनाने में उपयोग करने के लिए एक बहुत शक्तिशाली (आवश्यक) उपकरण है। हालाँकि जब इसका ठीक से उपयोग नहीं किया जाता है (जब इसका उपयोग ऑब्जेक्ट संरचनाओं को बनाने के अलावा किसी और चीज के लिए किया जाता है ) तो यह कोड बनाता है जो बहुत कसकर युग्मित होता है और बनाए रखने के लिए बहुत कठिन होता है।

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

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

--- संपादित करें इस उत्तर को और अधिक सामान्य शब्दों में प्रश्न का उत्तर देने के लिए एक बहुत अच्छा तर्क है।


3
(कार्यान्वयन) ओओ संरचनाओं को बनाने के लिए वंशानुक्रम आवश्यक नहीं है । आपके पास इसके बिना एक ओओ भाषा हो सकती है।
एंड्रेस एफ।

क्या आप एक उदाहरण प्रदान कर सकते हैं? मैंने विरासत के बिना OO कभी नहीं देखा है।
न्यूटॉपियन

1
समस्या यह है कि OOP क्या है, इसकी कोई स्वीकृत परिभाषा नहीं है। (एक तरफ, यहां तक ​​कि एलन काय अपनी परिभाषा की आम व्याख्या पर पछतावा करने के लिए आया था, जिसमें "संदेश" के बजाय "वस्तुओं" पर वर्तमान जोर दिया गया था)। यहाँ आपके प्रश्न के उत्तर में एक प्रयास है । मैं मानता हूँ कि विरासत के बिना OOP देखना असामान्य है; इसलिए मेरा तर्क सिर्फ इतना था कि यह आवश्यक नहीं है ;)
एंड्रेस एफ।

9

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

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

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


6

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


5

क्योंकि आप केवल एक वर्ग का विस्तार कर सकते हैं, जबकि आप कई इंटरफेस लागू कर सकते हैं।

मैंने एक बार सुना था कि वंशानुक्रम यह परिभाषित करता है कि आप क्या हैं, लेकिन इंटरफेस एक भूमिका को परिभाषित करते हैं जिसे आप निभा सकते हैं।

Interfaces भी बहुरूपता के बेहतर उपयोग के लिए अनुमति देते हैं।

वह कारण हो सकता है।


डाउनवोट क्यों?
महमूद होसम

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

@ जॉनमोच मैं डिजाइन पसंद नहीं कर रहा हूं गोसलिंग, मैं केवल एक कोडर को सलाह दे रहा हूं, कोडर्स आमतौर पर भाषा डिजाइन के साथ परेशान नहीं करते हैं।
महमूद होसम

1

मुझे यह भी सिखाया गया है और मैं जहां संभव हो इंटरफेस पसंद करता हूं (निश्चित रूप से मैं अभी भी विरासत का उपयोग करता हूं जहां समझ है)।

एक बात मुझे लगता है कि यह विशिष्ट कार्यान्वयन से आपके कोड को कम कर देती है। कहो कि मेरे पास कंसोलवर्टर नामक एक वर्ग है और वह कुछ लिखने के लिए एक विधि में पारित हो जाता है और इसे कंसोल पर लिख देता है। अब मैं कहता हूँ कि मैं GUI विंडो पर मुद्रण करना चाहता हूँ। खैर अब मुझे या तो विधि को संशोधित करना होगा या एक नया लिखना होगा जो GUIWriter को एक पैरामीटर के रूप में लेगा। अगर मैंने एक IWriter इंटरफ़ेस को परिभाषित करके शुरू किया था और IWriter में विधि लेता था जिसे मैं ConsoleWriter के साथ शुरू कर सकता था (जो IWriter इंटरफ़ेस को लागू करेगा) और फिर बाद में GUIWriter नामक एक नया वर्ग (जो IWriter इंटरफ़ेस को लागू करता है) लिखता है और फिर मैं बस पास होने वाले वर्ग को बंद करना होगा।

एक और बात (जो सी # के लिए सच है, जावा के बारे में निश्चित नहीं है) यह है कि आप केवल 1 वर्ग का विस्तार कर सकते हैं लेकिन कई इंटरफेस को लागू कर सकते हैं। बता दें कि मेरे पास टीचर, मैथ टीचर और हिस्ट्री टीचर नाम की कक्षाएं थीं। अब MathTeacher और HistoryTeacher का विस्तार शिक्षक से होता है लेकिन क्या होगा अगर हम एक ऐसा वर्ग चाहते हैं जो किसी ऐसे व्यक्ति का प्रतिनिधित्व करे जो MathTeacher और HistoryTeacher दोनों हो। जब आप केवल एक ही समय में एक कर सकते हैं (कई तरीके हैं, लेकिन वे बिल्कुल इष्टतम नहीं हैं) तो कई वर्गों से विरासत की कोशिश करते समय यह बहुत गड़बड़ हो सकता है। इंटरफेस के साथ आपके पास 2 इंटरफेस हो सकते हैं जिन्हें IMathTeacher और IHistoryTeacher कहा जाता है और फिर एक वर्ग होता है जो शिक्षक से विस्तारित होता है और उन 2 इंटरफेस को लागू करता है।

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

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


2
"आप केवल 1 वर्ग का विस्तार कर सकते हैं लेकिन कई इंटरफेस लागू कर सकते हैं" यह जावा के साथ-साथ सी # के लिए भी सही है।
फ्रस्ट्रेटेडविथफॉर्म्सडिजेनर

कोड दोहराव की समस्या का एक संभावित समाधान एक अमूर्त वर्ग बनाना है जो इंटरफ़ेस को लागू करता है और इसे विस्तारित करता है। देखभाल के साथ प्रयोग, हालांकि; वहाँ केवल कुछ मामलों में मैंने देखा है कि यह समझ में आता है।
माइकल के

0

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


2
एक नाइटपैकिंग: सर्कल-एलिप्से समस्या तब भी होगी, भले ही केवल शुद्ध इंटरफेस का उपयोग किया जाए, अगर वस्तुओं को परस्पर बदलना है।
11'11
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.