जावा मल्टीपल इनहेरिटेंस


168

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

मैं कक्षा है कहते हैं कि चलो Animalइस उप वर्ग हैं Birdऔर Horseऔर मैं एक वर्ग बनाने की जरूरत है Pegasusकि तक फैली हुई है Birdऔर Horseके बाद से Pegasusदोनों एक पक्षी और एक घोड़ा है।

मुझे लगता है कि यह क्लासिक हीरे की समस्या है। मैं इसे सुलझाने के लिए क्लासिक तरीके को समझ सकता हूं Animal, Birdऔर उनसे Horseइंटरफेस और कक्षाएं लागू Pegasusकरना है।

मैं सोच रहा था कि क्या समस्या को हल करने का एक और तरीका है जिसमें मैं अभी भी पक्षियों और घोड़ों के लिए ऑब्जेक्ट बना सकता हूं। अगर कोई ऐसा तरीका है जो जानवरों को भी पैदा करने में सक्षम है, तो यह बहुत अच्छा होगा लेकिन जरूरी नहीं है।


6
मुझे लगता है कि आप मैन्युअल रूप से कक्षाएं बना सकते हैं और उन्हें सदस्य के रूप में संग्रहीत कर सकते हैं (विरासत के बजाय संरचना)। प्रॉक्सी ( docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html ) वर्ग के साथ यह एक विकल्प हो सकता है, हालाँकि आपको इंटरफेस की भी आवश्यकता होगी।
गैबोर बाकोस

4
@ रैम को तब बर्ड का विस्तार नहीं करना चाहिए, बल्कि ऐसा व्यवहार करना चाहिए जिससे वह उड़ान भर सके। : D समस्या हल हुई
योगेश

11
बिल्कुल सही। कैसे एक इंटरफ़ेस के बारे में CanFly। :-)
आश्चर्यचकित नारियल

28
मुझे लगता है कि यह गलत तरीका है। आपके पास जानवर हैं - घोड़े, पक्षी। और आपके पास गुण हैं - फ्लाइंग, कार्निवोर। एक पेगासस एक हॉर्स बर्ड नहीं है यह एक घोड़ा है जो उड़ सकता है। गुणों को इंटरफेस में होना चाहिए। तो public class Pegasus extends Horse implements Flying
बोरिस द स्पाइडर

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

जवाबों:


115

आप जानवरों की कक्षाओं (जैविक अर्थ में वर्ग) के लिए इंटरफेस बना सकते हैं, जैसे कि public interface Equidaeघोड़ों के लिए और public interface Avialaeपक्षियों के लिए (मैं कोई जीवविज्ञानी नहीं हूं, इसलिए शर्तें गलत हो सकती हैं)।

तब आप अभी भी एक बना सकते हैं

public class Bird implements Avialae {
}

तथा

public class Horse implements Equidae {}

और भी

public class Pegasus implements Avialae, Equidae {}

टिप्पणियों से जोड़ना:

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

public abstract class AbstractHorse implements Equidae {}

public class Horse extends AbstractHorse {}

public class Pegasus extends AbstractHorse implements Avialae {}

अपडेट करें

मैं एक और विवरण जोड़ना चाहूंगा। जैसा कि ब्रायन ने कहा है , यह ओपी को पहले से ही पता है।

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


9
कौन सा ... ठीक वही है जो ओपी कहता है कि वे जानते हैं कि आप Q में कर सकते हैं।
ब्रायन रोच

4
जैसा कि पेगासस आईएस पहले से ही एक घोड़ा है (जो उड़ता है), मुझे लगता है कि आप अधिक कोड का पुन: उपयोग कर सकते हैं यदि हॉर्स और इम्प्लिमेंट्स का विस्तार किया जाता है।
पाब्लो लेज़ानो

8
मुझे यकीन नहीं है, मैंने अभी तक एक पेगासस नहीं देखा है। हालाँकि, उस स्थिति में मैं एक का उपयोग करना पसंद करूँगा AbstractHorse, जिसका उपयोग ज़ेबरा या अन्य घोड़े जैसे जानवरों के निर्माण के लिए भी किया जा सकता है।
मोरिट्ज़ पीटरसन

5
@MoritzPetersen यदि आप वास्तव में अमूर्त तत्वों के पुन: उपयोग और सार्थक नाम देना AbstractEquidaeचाहते हैं , तो शायद इससे अधिक उपयुक्त होगा AbstractHorse। ज़ेबरा को एक अमूर्त घोड़े का विस्तार करना अजीब होगा। अच्छा जवाब, वैसे।
afsantos

3
डक-टाइपिंग को Duckलागू करने में एक वर्ग कार्यान्वयन Avialaeभी शामिल होगा ?
मर्गिसिसा

88

वस्तुओं को एक साथ संयोजित करने के दो मूलभूत दृष्टिकोण हैं:

  • पहला है इनहेरिटेंस । जैसा कि आप पहले से ही विरासत की सीमाओं की पहचान कर चुके हैं, इसका मतलब है कि आप यहां वह नहीं कर सकते, जिसकी आपको जरूरत है।
  • दूसरी रचना है । चूंकि वंशानुक्रम विफल हो गया है इसलिए आपको रचना का उपयोग करने की आवश्यकता है।

जिस तरह से यह काम करता है कि आपके पास एक पशु वस्तु है। उस वस्तु के भीतर आप फिर आगे की वस्तुओं को जोड़ते हैं जो आपके लिए आवश्यक गुणों और व्यवहारों को देते हैं।

उदाहरण के लिए:

  • बर्ड फैली पशु औजार IFlier
  • हार्स फैली पशु औजार IHerbivore, IQuadruped
  • पेगासस फैली पशु औजार IHerbivore, IQuadruped, IFlier

अब IFlierबस इस तरह दिखता है:

 interface IFlier {
     Flier getFlier();
 }

तो Birdऐसा दिखता है:

 class Bird extends Animal implements IFlier {
      Flier flier = new Flier();
      public Flier getFlier() { return flier; }
 }

अब आपके पास इनहेरिटेंस के सभी फायदे हैं। आप कोड का फिर से उपयोग कर सकते हैं। आपके पास IFliers का संग्रह हो सकता है, और बहुरूपता के सभी अन्य लाभों का उपयोग कर सकता है, आदि।

हालाँकि आपके पास संरचना से सभी लचीलेपन भी हैं। आप प्रत्येक प्रकार की तरह Animal- जैसे कि आप प्रत्येक बिट को कैसे सेट किया जाता है, इस पर बहुत अधिक नियंत्रण के साथ आप कई अलग-अलग इंटरफेस और समग्र बैकिंग क्लास के रूप में आवेदन कर सकते हैं ।

रचना के लिए रणनीति पैटर्न वैकल्पिक दृष्टिकोण

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


एक समान विकल्प भी प्रकार की कक्षाओं का उपयोग करना हो सकता है, हालांकि वे जावा में उपयोग करने के लिए इतने स्वाभाविक नहीं हैं (आपको कनवर्टर विधियों का उपयोग करना होगा और इसी तरह), यह विचार प्राप्त करने के लिए उपयोगी हो सकता है: typeclassopedia.bitbucket.org
Gbbor Bakos

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

लेकिन getFlier()हर तरह के पक्षी के लिए फिर से लागू किया जाना चाहिए।
SMUsamaShah

1
@ LifeH2O उन्हें साझा कार्यक्षमता के ब्लॉक में विभाजित करें और फिर उन्हें दें। यानी आपके पास हो सकता है MathsTeacherऔर EnglishTeacherदोनों विरासत Teacherमें मिले ChemicalEngineer, MaterialsEngineerआदि EngineerTeacherऔर Engineerदोनों लागू होते हैं ComponentPersonफिर बस की एक सूची है Component, और आप उन्हें सही दे सकते हैं Componentकि के लिए रों Person। अर्थात् person.getComponent(Teacher.class), person.getComponent(MathsTeacher.class)आदि
टिम बी

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

43

मेरे पास एक बेवकूफ विचार है:

public class Pegasus {
    private Horse horseFeatures; 
    private Bird birdFeatures; 

   public Pegasus(Horse horse, Bird bird) {
     this.horseFeatures = horse;
     this.birdFeatures = bird;
   }

  public void jump() {
    horseFeatures.jump();
  }

  public void fly() {
    birdFeatures.fly();
  }
}

24
यह काम करेगा, लेकिन मुझे उस तरह का दृष्टिकोण (रैपर) पसंद नहीं है क्योंकि तब लगता है कि पेगासस एक घोड़ा है, इसके बजाय यह एक घोड़ा है।
पाब्लो लेज़ानो

धन्यवाद। मैं अपने आप को विचार पोस्ट करने में मदद नहीं कर सका। मुझे पता है कि यह बेवकूफ है, लेकिन मैंने यह नहीं देखा कि यह बेवकूफी क्यों है ...
पावेल जैनिस

3
यह लगभग टिम बी के जवाब से रचना दृष्टिकोण के एक अपरिष्कृत संस्करण की तरह है।
चरण

1
इसे करने का तरीका कमोबेश स्वीकृत तरीका है, हालांकि आपके पास IJumps जैसा एक "जंप" पद्धति भी होनी चाहिए जो कि हॉर्स और पेगासस और आईफ्लाइज़ द्वारा "फ्लाई" पद्धति के साथ लागू किया जाता है जो कि बर्ड और पेगासस द्वारा लागू किया जाता है।
MatsT

2
@ पाब्लो नं, एक पेगासस एचए हॉर्सफ़्रीचर और एचएएस बर्डफ़्रीचर। +1 के उत्तर के लिए क्योंकि यह कोड को सरल रखता है, क्लंकियर, वर्ग-स्पैनिंग, उचित जावा समाधानों के विपरीत।
जेनगूडल

25

क्या मुझे डक-टाइपिंग की अवधारणा सुझानी चाहिए ?

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

इस तरह की अवधारणा का उपयोग रणनीति पैटर्न में किया जाता है । दिए गए उदाहरण वास्तव में दिखाता है कि एक बतख inherits FlyBehaviourऔर QuackBehaviourऔर अभी भी वहाँ बत्तख, हो सकता है जैसे RubberDuck, उड़ नहीं सकता है। वे Duckविस्तार को एक Birdवर्ग भी बना सकते थे, लेकिन तब उन्होंने कुछ लचीलापन छोड़ दिया होता, क्योंकि हर Duckकोई उड़ान भरने में सक्षम होता, यहां तक ​​कि गरीब भी RubberDuck


19

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


13

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


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

@ मिक्केल लोंके: पेगासस वर्ग को अस्पष्ट तरीकों के लिए ओवरराइड को परिभाषित करना है लेकिन उन्हें केवल सुपर विधि (या एक चुने हुए क्रम में दोनों) को सौंपकर लागू कर सकते हैं।
होल्गर

12

घोड़े को आधे दरवाजे के साथ स्थिर रखना सुरक्षित है, क्योंकि घोड़ा आधे दरवाजे पर नहीं पहुंच सकता। इसलिए मैं एक घोड़ा आवास सेवा स्थापित करता हूं जो किसी भी प्रकार के घोड़े को स्वीकार करता है और इसे आधे दरवाजे के साथ स्थिर में रखता है।

तो क्या जानवर जैसा घोड़ा है जो घोड़ा भी उड़ सकता है?

मैं कई विरासतों के बारे में बहुत सोचता था, हालांकि अब जब मैं 15 वर्षों से प्रोग्रामिंग कर रहा हूं, तो मुझे कई विरासतों को लागू करने के बारे में कोई परवाह नहीं है।

अधिक बार नहीं, जब मैंने एक डिज़ाइन के साथ सामना करने की कोशिश की है, जो कई उत्तराधिकार की ओर इशारा करता है, तो मैं बाद में रिलीज करने के लिए आया हूं कि मुझे याद आया कि समस्या डोमेन को समझ गई थी।

या

यदि यह एक बतख की तरह दिखता है और बतख की तरह है, लेकिन इसे बैटरी की जरूरत है, तो आपको शायद गलत अमूर्तता है


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

8

जावा में मल्टीपल इनहेरिटेंस की समस्या नहीं है, क्योंकि इसमें मल्टीपल इनहेरिटेंस नहीं है। यह वास्तविक बहु विरासत समस्या (हीरे की समस्या) को हल करने के लिए डिजाइन द्वारा है।

समस्या को कम करने के लिए अलग-अलग रणनीतियाँ हैं। सबसे तुरंत प्राप्त होने वाली समग्र वस्तु है जिसे पावेल सुझाव देता है (अनिवार्य रूप से सी ++ इसे कैसे संभालता है)। मुझे नहीं पता कि जावा के भविष्य के लिए कार्डों पर C3 रैखिककरण (या समान) के माध्यम से कई विरासत हैं, लेकिन मुझे संदेह है।

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


6

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

यदि आप अपने पेगासस वर्ग के अंदर अपने हार्स और बर्ड कार्यान्वयन के तरीकों और सुविधाओं का उपयोग करने में सक्षम होना चाहते हैं, तो आप पेगासस को एक बर्ड और एक हॉर्स की संरचना के रूप में लागू कर सकते हैं :

public class Animals {

    public interface Animal{
        public int getNumberOfLegs();
        public boolean canFly();
        public boolean canBeRidden();
    }

    public interface Bird extends Animal{
        public void doSomeBirdThing();
    }
    public interface Horse extends Animal{
        public void doSomeHorseThing();
    }
    public interface Pegasus extends Bird,Horse{

    }

    public abstract class AnimalImpl implements Animal{
        private final int numberOfLegs;

        public AnimalImpl(int numberOfLegs) {
            super();
            this.numberOfLegs = numberOfLegs;
        }

        @Override
        public int getNumberOfLegs() {
            return numberOfLegs;
        }
    }

    public class BirdImpl extends AnimalImpl implements Bird{

        public BirdImpl() {
            super(2);
        }

        @Override
        public boolean canFly() {
            return true;
        }

        @Override
        public boolean canBeRidden() {
            return false;
        }

        @Override
        public void doSomeBirdThing() {
            System.out.println("doing some bird thing...");
        }

    }

    public class HorseImpl extends AnimalImpl implements Horse{

        public HorseImpl() {
            super(4);
        }

        @Override
        public boolean canFly() {
            return false;
        }

        @Override
        public boolean canBeRidden() {
            return true;
        }

        @Override
        public void doSomeHorseThing() {
            System.out.println("doing some horse thing...");
        }

    }

    public class PegasusImpl implements Pegasus{

        private final Horse horse = new HorseImpl();
        private final Bird bird = new BirdImpl();


        @Override
        public void doSomeBirdThing() {
            bird.doSomeBirdThing();
        }

        @Override
        public int getNumberOfLegs() {
            return horse.getNumberOfLegs();
        }

        @Override
        public void doSomeHorseThing() {
            horse.doSomeHorseThing();
        }


        @Override
        public boolean canFly() {
            return true;
        }

        @Override
        public boolean canBeRidden() {
            return true;
        }
    }
}

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

इकाई-घटक-प्रणाली के दृष्टिकोण के लिए कुछ छद्म कोड इस तरह दिख सकते हैं:

public void createHorse(Entity entity){
    entity.setComponent(NUMER_OF_LEGS, 4);
    entity.setComponent(CAN_FLY, false);
    entity.setComponent(CAN_BE_RIDDEN, true);
    entity.setComponent(SOME_HORSE_FUNCTIONALITY, new HorseFunction());
}

public void createBird(Entity entity){
    entity.setComponent(NUMER_OF_LEGS, 2);
    entity.setComponent(CAN_FLY, true);
    entity.setComponent(CAN_BE_RIDDEN, false);
    entity.setComponent(SOME_BIRD_FUNCTIONALITY, new BirdFunction());
}

public void createPegasus(Entity entity){
    createHorse(entity);
    createBird(entity);
    entity.setComponent(CAN_BE_RIDDEN, true);
}

4

आपके पास एक इंटरफ़ेस पदानुक्रम हो सकता है और फिर चयनित इंटरफ़ेस से अपनी कक्षाओं का विस्तार कर सकते हैं:

public interface IAnimal {
}

public interface IBird implements IAnimal {
}

public  interface IHorse implements IAnimal {
}

public interface IPegasus implements IBird,IHorse{
}

और फिर एक विशिष्ट इंटरफ़ेस का विस्तार करके अपनी कक्षाओं को आवश्यकतानुसार परिभाषित करें:

public class Bird implements IBird {
}

public class Horse implements IHorse{
}

public class Pegasus implements IPegasus {
}

1
या वह बस कर सकता है: सार्वजनिक वर्ग पेगासस जानवरों के घोड़े, पक्षी
बैटमैन

ओपी को इस समाधान के बारे में पहले से ही पता है कि वह इसे करने के लिए वैकल्पिक रास्ता तलाश रहा है
योगेश

@ बाटमैन, बेशक वह कैनम करता है लेकिन अगर वह पदानुक्रम का विस्तार करना चाहता है, तो उसे इस दृष्टिकोण का पालन करने की आवश्यकता होगी
richardtz

IBirdऔर इसके बजाय IHorseलागू करना चाहिएIAnimalAnimal
oliholz

@ योगेश, आप सही कह रहे हैं। मैंने उस जगह की अनदेखी की जहां वह इसे बताता है। "नौसिखिया" के रूप में मुझे अब क्या करना चाहिए, उत्तर को हटा दें, या इसे वहां छोड़ दें? धन्यवाद।
रीचर्डज़

4

एहम, आपकी कक्षा केवल 1 अन्य के लिए उपवर्ग हो सकती है, लेकिन फिर भी, आपके पास जितने चाहें लागू हो सकते हैं।

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

अपने मामले की तरह आप कह सकते हैं:

abstract class Animal {
   private Integer hp = 0; 
   public void eat() { 
      hp++; 
   }
}
interface AirCompatible { 
   public void fly(); 
}
class Bird extends Animal implements AirCompatible { 
   @Override
   public void fly() {  
       //Do something useful
   }
} 
class Horse extends Animal {
   @Override
   public void eat() { 
      hp+=2; 
   }

}
class Pegasus extends Horse implements AirCompatible {
   //now every time when your Pegasus eats, will receive +2 hp  
   @Override
   public void fly() {  
       //Do something useful
   }
}

3

इंटरफेस कई विरासत का अनुकरण नहीं करते हैं। जावा निर्माता कई विरासत को गलत मानते हैं, इसलिए जावा में ऐसी कोई चीज नहीं है।

यदि आप दो वर्गों की कार्यक्षमता को एक में संयोजित करना चाहते हैं - ऑब्जेक्ट रचना का उपयोग करें। अर्थात

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}

और यदि आप कुछ विधियों को उजागर करना चाहते हैं, तो उन्हें परिभाषित करें और उन्हें कॉल को संबंधित नियंत्रक को सौंपने दें।

यहाँ इंटरफेस काम आ सकते हैं - यदि Component1इंटरफ़ेस Interface1और Component2इम्प्लीमेंट लागू होते हैं Interface2, तो आप परिभाषित कर सकते हैं

class Main implements Interface1, Interface2

ताकि आप वस्तुओं का परस्पर उपयोग कर सकें जहाँ संदर्भ इसकी अनुमति देता है।

तो मेरी बात में, आप हीरे की समस्या में नहीं पड़ सकते।


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

3

जैसा कि आप पहले से ही जानते होंगे, जावा में कई वर्गों की विरासत संभव नहीं है, लेकिन इंटरफेस के साथ यह संभव है। आप रचना डिज़ाइन पैटर्न का उपयोग करने पर भी विचार कर सकते हैं।

मैंने कुछ साल पहले रचना पर एक बहुत व्यापक लेख लिखा था ...

/codereview/14542/multiple-inheritance-and-composition-with-java-and-c-updated


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

बेहतर समझ के लिए नीचे दिए गए उदाहरण देखें

डेकोरेटर पैटर्न का उपयोग कब करें?


2

जटिलता को कम करने और भाषा को सरल बनाने के लिए जावा में कई विरासत का समर्थन नहीं किया जाता है।

एक परिदृश्य पर विचार करें जहां ए, बी और सी तीन वर्ग हैं। C वर्ग को A और B वर्ग विरासत में मिला है। यदि ए और बी कक्षाओं में एक ही विधि है और आप इसे चाइल्ड क्लास ऑब्जेक्ट से कहते हैं, तो ए या बी क्लास की कॉल विधि की अस्पष्टता होगी।

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

class A {  
    void msg() {
        System.out.println("From A");
    }  
}

class B {  
    void msg() {
        System.out.println("From B");
    }  
}

class C extends A,B { // suppose if this was possible
    public static void main(String[] args) {  
        C obj = new C();  
        obj.msg(); // which msg() method would be invoked?  
    }
} 

2

जावा → इंटरफ़ेस में म्यूटेंट इनहेरिटेंस की समस्या को हल करने के लिए उपयोग किया जाता है

J2EE (कोर JAVA) नोट्स श्री केवीआर पृष्ठ 51 द्वारा

दिन - २ 27

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

एक इंटरफ़ेस एक निर्माण है जिसमें विशुद्ध रूप से अपरिभाषित विधियों का संग्रह होता है या एक इंटरफ़ेस विशुद्ध रूप से सार विधियों का एक संग्रह होता है।

[...]

दिन - 28:

वर्ग के लिए इंटरफ़ेस की सुविधाओं के पुन: उपयोग के लिए सिंटैक्स -1:

[abstract] class <clsname> implements <intf 1>,<intf 2>.........<intf n>
{
    variable declaration;
    method definition or declaration;
};

उपरोक्त सिंटैक्स में clsname उस वर्ग के नाम का प्रतिनिधित्व करता है जो 'n' संख्या के इंटरफेस से सुविधाओं को प्राप्त कर रहा है। 'इम्प्लीमेंट्स ’एक ऐसा कीवर्ड है, जिसका उपयोग इंटरफेस (एस) की विशेषताओं को एक व्युत्पन्न वर्ग के लिए किया जाता है।

[...]

सिंटैक्स -2 को दूसरे इंटरफ़ेस में 'n' इंटरफेस की संख्या:

interface <intf 0 name> extends <intf 1>,<intf 2>.........<intf n>
{     
    variable declaration cum initialization;
    method declaration;
};

[...]

सिंटेक्स-3:

[abstract] class <derived class name> extends <base class name> implements <intf 1>,<intf 2>.........<intf n>
{
  variable declaration;
  method definition or declaration;
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.