2008-09-23 8 views
20

मैं जावा को एक उदाहरण के रूप में चुनूंगा, ज्यादातर लोग इसे जानते हैं, हालांकि हर दूसरी ओओ भाषा भी काम कर रही थी।ओओपी है और पूरी तरह से कार्यान्वयन विरासत से परहेज संभव है?

जावा, कई अन्य भाषाओं की तरह, इंटरफेस विरासत और कार्यान्वयन विरासत है। जैसे एक जावा क्लास एक और एक विधि से उत्तराधिकारी हो सकती है जिसमें कार्यान्वयन होता है (मानते हैं कि अभिभावक अमूर्त नहीं है) भी विरासत में है। इसका मतलब है कि इंटरफ़ेस विरासत में मिला है और इस विधि के लिए कार्यान्वयन भी है। मैं इसे ओवरराइट कर सकता हूं, लेकिन मुझे यह नहीं करना है। अगर मैं इसे ओवरराइट नहीं करता हूं, तो मुझे कार्यान्वयन विरासत में मिला है।

हालांकि, मेरी कक्षा कार्यान्वयन के बिना, केवल "इंटरफ़ेस" (जावा शर्तों में नहीं) को "इंटरफ़ेस" भी दे सकती है। वास्तव में जावा में वास्तव में इंटरफेस का नाम दिया जाता है, वे इंटरफ़ेस विरासत प्रदान करते हैं, लेकिन किसी भी कार्यान्वयन को विरासत के बिना, क्योंकि इंटरफ़ेस के सभी तरीकों में कोई कार्यान्वयन नहीं होता है।

अब यह article, saying it's better to inherit interfaces than implementations था, आप इसे पढ़ना चाहेंगे (कम से कम पहले पृष्ठ का पहला भाग), यह बहुत दिलचस्प है। यह fragile base class problem जैसे मुद्दों से बचाता है। अब तक यह सब कुछ समझ में आता है और लेख में कई अन्य चीजें जो मुझे बहुत समझ में आती हैं।

मुझे इसके बारे में क्या बग है, यह कार्यान्वयन विरासत का अर्थ है कोड पुन: उपयोग, ओओ भाषाओं के सबसे महत्वपूर्ण गुणों में से एक है। अब यदि जावा में कोई वर्ग नहीं था (जैसे जेम्स गोस्लिंग, जावा के गॉडफादर ने इस लेख के अनुसार कामना की है), यह कार्यान्वयन विरासत की सभी समस्याओं को हल करता है, लेकिन फिर आप कोड पुन: उपयोग कैसे कर सकते हैं?

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

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

कुछ भाषाओं में मिक्सिन हैं। क्या मिक्सिन मेरे प्रश्न का उत्तर हैं? मैंने उनके बारे में पढ़ा, लेकिन मैं वास्तव में कल्पना नहीं कर सकता कि कैसे मैजिकिन जावा दुनिया में काम करेगा और यदि वे वास्तव में समस्या को हल कर सकते हैं।

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

public void move() { 
    abstractCarObject.move(); 
} 

तरह डमी तरीकों लिखने के लिए है?

कोई भी बेहतर विचार कल्पना कर सकता है कि कार्यान्वयन विरासत से कैसे बचें और फिर भी एक आसान फैशन में कोड का पुनः उपयोग करने में सक्षम हो?

+0

यह "इंटरफेस विरासत" लेकिन "इंटरफेस कार्यान्वयन" कॉल करने के लिए पसंद नहीं है। यह एक चीज है जिसे मैं वास्तव में जावा भाषा से पसंद करता हूं, तदनुसार दो अलग-अलग अवधारणाएं। – Trap

उत्तर

11

संक्षिप्त उत्तर: हाँ यह संभव है। लेकिन अगर आपने जानबूझकर यह क्या करना है और कोई संयोग से (का उपयोग करते हुए अंतिम, सार और डिजाइन को ध्यान में विरासत के साथ, आदि)

लांग जवाब:

ठीक है, विरासत नहीं वास्तव में "कोड को फिर से उपयोग के लिए है ", यह कक्षा" विशेषज्ञता "के लिए है, मुझे लगता है कि यह एक गलत व्याख्या है।

उदाहरण के लिए वे एक वेक्टर से स्टैक बनाने का एक बहुत बुरा विचार है, सिर्फ इसलिए कि वे समान हैं। या हैशटेबल से गुण सिर्फ इसलिए कि वे मूल्यों को संग्रहित करते हैं। [प्रभावी] देखें।

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

यह "कोड पुन: उपयोग" का एक पहलू है। दूसरा प्रभावी ढंग से है, जिसे प्रोग्रामिंग के साथ करना है।लेकिन इस मामले में कोड की रेखाओं को "सहेजने" और नाजुक राक्षसों को बनाने के लिए नहीं, बल्कि दिमाग में दिमाग के साथ डिजाइन करना है। पहले उल्लिखित पुस्तक में यह आइटम 17 है; आइटम 17: विरासत के लिए डिज़ाइन और दस्तावेज़ या अन्यथा इसे प्रतिबंधित करें। देखें [प्रभावी]

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

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

जब आप इस तरह आगे बढ़ते हैं, तो "नाजुक" वर्ग (या कम से कम डिजाइनर जागरूक या खतरा) के साथ कोई समस्या नहीं है और उप-वर्ग केवल उन हिस्सों को पूरा करते हैं जो डिजाइनर उन्हें अनुमति देते हैं।

विरासत कक्षाओं को "विशेषज्ञ" करने के लिए और अधिक है, उसी तरह एक ट्रक कार का एक विशेष संस्करण है, और मोस्टरट्रुक ट्रक का एक विशेष संस्करण है।

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

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

उप-वर्गीकरण उद्देश्य पर किए जाने पर बुरा नहीं है। अगर यह अनजाने में किया जाता है तो यह एक दुःस्वप्न बन सकता है। मैं कहूंगा कि आपको जितना संभव हो सके निजी और "अंतिम" शुरू करना चाहिए और यदि आवश्यक हो तो चीजों को और अधिक सार्वजनिक और विस्तारित करें। प्रस्तुति में यह व्यापक रूप से समझाया गया है कि "अच्छी एपीआई कैसे डिजाइन करें और यह क्यों मायने रखता है" देखें [अच्छा एपीआई]

लेख पढ़ना जारी रखें और समय और अभ्यास (और बहुत धैर्य) के साथ यह बात स्पष्ट हो जाएगी। हालांकि कभी-कभी आपको केवल काम करने की आवश्यकता होती है और कुछ कोड कॉपी/पेस्ट करना पड़ता है: पी। यह ठीक है, जब तक आप इसे पहले अच्छी तरह से करने की कोशिश करते हैं।

यहाँ दोनों यहोशू बलोच


[प्रभावी] प्रभावी जावा (पूर्व में जावा के मूल अब गूगल के लिए काम पर सूर्य में काम कर) से संदर्भ हैं। निश्चित रूप से सर्वश्रेष्ठ जावा पुस्तक एक गैर नौसिखिया को सीखना, समझना और अभ्यास करना चाहिए। यह आपके पास होना ही चाहिए।

Effective Java


[अच्छा एपीआई] प्रस्तुति कि एपीआई डिजाइन, पुनर्प्रयोग और संबंधित विषयों पर बात करती है। यह थोड़ा लंबा है लेकिन यह हर मिनट के लायक है।

How To Design A Good API and Why it Matters

सादर।


अद्यतन: मैंने आपके द्वारा भेजे गए वीडियो लिंक के मिनट 42 पर एक नज़र डालें।यह इस विषय के बारे में बात करता है:

"जब आपके पास सार्वजनिक एपीआई में दो कक्षाएं होती हैं और आप एक दूसरे के उप-वर्ग को बनाने के बारे में सोचते हैं, जैसे फू बार का उप-वर्ग है, तो अपने आप से पूछें, क्या हर फू बार है? .. "

और पिछले मिनट में यह टाइमटास्क के बारे में बात करते समय" कोड पुन: उपयोग "के बारे में बात करता है।

+0

गंभीरता से, मैं यह देखने में असफल रहा कि एक कार से ट्रक को कैसे प्राप्त किया जाना चाहिए :) – Trap

+2

शायद ट्रक और कारों को ऑटोमोबाइल से प्राप्त होना चाहिए। :-) – StriplingWarrior

4

आप रचना और रणनीति पैटर्न का भी उपयोग कर सकते हैं। link text

public class Car 
{ 
    private ICar _car; 

    public void Move() { 
    _car.Move(); 
    } 
} 

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

2

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

0

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

कुछ एल्गोरिदम के लिए कुछ उपयोगी कार्य करने के लिए प्रोग्रामिंग के असंख्य तत्वों को एक साथ कैसे रखा जाए, यह दिखाने में आंख खोलना है। डिज़ाइन पैटर्न ऑब्जेक्ट्स के लिए समान होते हैं। आपको एक उपयोगी कार्य करने के लिए ऑब्जेक्ट्स को गठबंधन करने के तरीके दिखाता है।

Design Patterns by the Gang of Four

2

mixins/रचना आसान बनाने के लिए, मेरे एनोटेशन और एनोटेशन प्रोसेसर पर एक नज़र डालें:

http://code.google.com/p/javadude/wiki/Annotations

विशेष रूप से, mixins उदाहरण:

http://code.google.com/p/javadude/wiki/AnnotationsMixinExample

ध्यान दें कि यह वर्तमान में काम नहीं करता है अगर इंटरफ़ेस एसेस/प्रकारों को पैरामीटरयुक्त विधियों (या तरीकों पर पैरामीटरयुक्त प्रकार) के लिए प्रतिनिधि दिया जा रहा है। मैं उस पर काम कर रहा हूं ...

+0

यह कुछ सुंदर दिलचस्प चीजें हैं, आपके पास है। मैं इसे एक विस्तृत रूप से देखूंगा :) – Mecki

8

विरासत के खिलाफ सबसे अधिक उदाहरण के साथ समस्या उदाहरण हैं जहां व्यक्ति विरासत का उपयोग गलत तरीके से कर रहा है, विरासत की सही विफलता की विफलता नहीं।

लेख में आपने एक लिंक पोस्ट किया है, लेखक स्टैक और ऐरेलिस्ट का उपयोग करके विरासत की "टूटाई" दिखाता है। उदाहरण त्रुटिपूर्ण है क्योंकि एक स्टैक एक ArrayList नहीं है और इसलिए विरासत का उपयोग नहीं किया जाना चाहिए। उदाहरण स्ट्रिंग विस्तारित वर्ण, या प्वाइंटएक्सई विस्तार संख्या के रूप में त्रुटिपूर्ण है।

कक्षा बढ़ाने से पहले, आपको हमेशा "is_a" परीक्षण करना चाहिए। चूंकि आप यह नहीं कह सकते कि हर स्टैक किसी भी तरह से गलत होने के बिना एक ऐरेलिस्ट है, तो आपको शर्मिंदा नहीं होना चाहिए।

स्टैक के लिए अनुबंध ArrayList (या सूची) के अनुबंध से अलग है और ढेर विरासत विधियों को नहीं होना चाहिए जिनकी परवाह नहीं है (जैसे (int i) और जोड़ें())।

interface Stack<T> { 
    public void push(T object); 
    public T pop(); 
    public void clear(); 
    public int size(); 
} 

ArrayListStack की तरह एक वर्ग ढेर इंटरफ़ेस को लागू कर सकते हैं, और उस मामले उपयोग संरचना में (एक आंतरिक ArrayList वाले) और नहीं विरासत: वास्तव में ढेर जैसे तरीकों के साथ एक इंटरफेस होना चाहिए।

विरासत खराब नहीं है, बुरा विरासत खराब है।

0

ऑब्जेक्ट उन्मुख भाषा के लिए विरासत आवश्यक नहीं है।

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

2

मेरे अपने प्रश्न का उत्तर देना मजाकिया है, लेकिन यहां कुछ ऐसा पाया गया है जो बहुत दिलचस्प है: Sather

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

भाषा इतनी सुंदर नहीं है, लेकिन मैं इसे पीछे विचार यह प्यार :-) मैं एक के लिए

संबंधित मुद्दे