"मेमोरी के लिए भयानक" तर्क पूरी तरह से गलत है, लेकिन यह एक उद्देश्यपूर्ण "बुरा अभ्यास" है। जब आप एक वर्ग से विरासत में लेते हैं, तो आप केवल उन क्षेत्रों और विधियों को विरासत में नहीं लेते हैं जिनकी आप रुचि रखते हैं। इसके बजाय, आपको सब कुछ विरासत में मिलता है । हर वह तरीका जो वह घोषित करता है, भले ही वह आपके लिए उपयोगी न हो। और सबसे महत्वपूर्ण बात, आप इसके सभी अनुबंधों की भी गारंटी लेते हैं और गारंटी देते हैं कि वर्ग प्रदान करता है।
संक्षिप्त SOLID अच्छी वस्तु उन्मुख डिजाइन के लिए कुछ उत्तराधिकार प्रदान करता है। यहाँ, I nterface Segregation Principle (ISP) और L iskov एवोल्यूशन प्राइसिंग (LSP) कुछ कहना है।
आईएसपी हमें अपने इंटरफेस को यथासंभव छोटा रखने के लिए कहता है। लेकिन विरासत में मिलने से ArrayList
, आपको कई, कई तरीके मिलते हैं। यह करने के लिए सार्थक है get()
, remove()
, set()
(की जगह), या add()
एक विशेष सूचकांक में (डालने) एक बच्चे नोड? क्या यह ensureCapacity()
अंतर्निहित सूची के लिए समझदार है ? यह sort()
एक नोड के लिए क्या मतलब है ? क्या आपकी कक्षा के उपयोगकर्ता वास्तव में ए पाने वाले हैं subList()
? चूँकि आप उन तरीकों को नहीं छिपा सकते जो आप नहीं चाहते हैं, एकमात्र समाधान ArrayList को एक सदस्य चर के रूप में रखना है, और उन सभी तरीकों को अग्रेषित करना है जो आप वास्तव में चाहते हैं:
private final ArrayList<Node> children = new ArrayList();
public void add(Node child) { children.add(child); }
public Iterator<Node> iterator() { return children.iterator(); }
यदि आप वास्तव में दस्तावेज़ में आपके द्वारा देखे गए सभी तरीकों को चाहते हैं, तो हम एलएसपी पर आगे बढ़ सकते हैं। एलएसपी हमें बताता है कि हमें उपवर्ग का उपयोग करने में सक्षम होना चाहिए जहां भी मूल वर्ग अपेक्षित है। यदि कोई फ़ंक्शन ArrayList
पैरामीटर के रूप में लेता है और हम Node
इसके बजाय पास करते हैं, तो कुछ भी नहीं बदलना चाहिए।
उपवर्गों की संगतता सरल चीजों से शुरू होती है जैसे कि हस्ताक्षर। जब आप किसी विधि को ओवरराइड करते हैं, तो आप पैरामीटर प्रकारों को अधिक सख्त नहीं बना सकते हैं क्योंकि यह उन उपयोगों को बाहर कर सकता है जो मूल वर्ग के साथ कानूनी थे। लेकिन यह जावा में हमारे लिए कंपाइलर चेक है।
लेकिन एलएसपी बहुत अधिक गहराई से चलता है: हमें उन सभी चीजों के साथ संगतता बनाए रखना होगा जो सभी मूल वर्गों और इंटरफेस के प्रलेखन द्वारा वादा किया गया है। में उनके जवाब , लिन ऐसे ही एक मामले में जहां पाया गया है List
इंटरफेस (आप के माध्यम से विरासत में मिला है जो ArrayList
) की गारंटी देता है कि कैसे equals()
और hashCode()
तरीके काम करने वाले हैं। के लिए hashCode()
आप भी एक विशेष एल्गोरिथ्म है कि वास्तव में लागू किया जाना चाहिए दिया जाता है। मान लेते हैं कि आपने यह लिखा है Node
:
public class Node extends ArrayList<Node> {
public final int value;
public Node(int value, Node... children) {
this.value = Value;
for (Node child : children)
add(child);
}
...
}
इसके लिए आवश्यक है कि इसमें value
कोई योगदान नहीं हो सकता है hashCode()
और यह प्रभावित नहीं कर सकता है equals()
। List
इंटरफ़ेस - जो आप इसे से इनहेरिट से सम्मानित करने के लिए वादा करता हूँ - की आवश्यकता है new Node(0).equals(new Node(123))
सच।
क्योंकि कक्षाओं से विरासत में यह एक माता-पिता द्वारा किए गए वादे को गलती से तोड़ना बहुत आसान हो जाता है, और क्योंकि यह आमतौर पर आपके द्वारा की गई अपेक्षा से अधिक तरीकों को उजागर करता है, यह आमतौर पर सुझाव दिया जाता है कि आप विरासत पर रचना पसंद करते हैं । यदि आपको कुछ विरासत में मिला है, तो यह केवल विरासत में मिली इंटरफेस का सुझाव है। यदि आप किसी विशेष वर्ग के व्यवहार का पुन: उपयोग करना चाहते हैं, तो आप इसे उदाहरण चर में एक अलग वस्तु के रूप में रख सकते हैं, इस तरह इसके सभी वादे और आवश्यकताएं आप पर मजबूर नहीं होती हैं।
कभी-कभी, हमारी प्राकृतिक भाषा एक विरासत संबंध का सुझाव देती है: एक कार एक वाहन है। मोटरसाइकिल एक वाहन है। क्या मुझे कक्षाओं को परिभाषित करना चाहिए Car
और Motorcycle
यह एक Vehicle
वर्ग से विरासत में मिला है ? ऑब्जेक्ट-ओरिएंटेड डिज़ाइन वास्तविक दुनिया को वास्तव में हमारे कोड में प्रतिबिंबित करने के बारे में नहीं है। हम आसानी से अपने स्रोत कोड में वास्तविक दुनिया के समृद्ध वर्गीकरण को सांकेतिक शब्दों में बदलना नहीं कर सकते हैं।
ऐसा ही एक उदाहरण कर्मचारी-बॉस मॉडलिंग समस्या है। हमारे पास कई Person
नाम हैं, प्रत्येक का नाम और पता है। एक Employee
है एक Person
और एक है Boss
। ए Boss
भी है Person
। तो क्या मुझे एक Person
वर्ग बनाना चाहिए जो विरासत में मिला है Boss
और Employee
? अब मुझे एक समस्या है: बॉस भी एक कर्मचारी है और एक और श्रेष्ठ है। तो ऐसा लगता है जैसे Boss
विस्तार करना चाहिए Employee
। लेकिन एक CompanyOwner
है, Boss
लेकिन एक नहीं है Employee
? किसी भी तरह का वंशानुक्रम ग्राफ किसी तरह यहाँ टूट जाएगा।
OOP पदानुक्रम, वंशानुक्रम और मौजूदा कक्षाओं के फिर से उपयोग के बारे में नहीं है, यह व्यवहार को सामान्य बनाने के बारे में है । यही कारण है कि है - OOP के बारे में "और मुझे परवाह नहीं है कैसे। मैं वस्तुओं का एक समूह है और उन्हें एक विशेष बात यह है कि क्या करना चाहते हैं" है इंटरफेस के लिए कर रहे हैं। यदि आप Iterable
इंटरफ़ेस को अपने लिए लागू करते हैं Node
क्योंकि आप इसे चलना चाहते हैं, तो यह पूरी तरह से ठीक है। यदि आप Collection
इंटरफ़ेस लागू करते हैं क्योंकि आप चाइल्ड नोड्स आदि जोड़ना / हटाना चाहते हैं, तो यह ठीक है। लेकिन एक अन्य वर्ग से विरासत में मिला क्योंकि ऐसा होता है कि आपको वह सब देना होगा, या कम से कम तब तक नहीं जब तक कि आपने इसे ऊपर बताए अनुसार सावधानीपूर्वक न सोचा हो।