ढीले युग्मन प्राप्त करने में सुपरक्लास की तुलना में इंटरफेस अधिक सहायक क्यों हैं?


15

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

ढीली युग्मन को एक ठोस प्रकार के बजाय एक अमूर्त पर निर्भर करते हुए प्राप्त किया जा सकता है।

यह दो मुख्य कारणों के लिए ढीली युग्मन की अनुमति देता है: 1- ठोस प्रकारों की तुलना में अमूर्तता कम होने की संभावना है, जिसका अर्थ है कि आश्रित कोड के टूटने की संभावना कम है। 2- विभिन्न ठोस प्रकारों का उपयोग रनटाइम पर किया जा सकता है, क्योंकि वे सभी अमूर्त रूप में फिट होते हैं। नए कंक्रीट प्रकारों को बाद में भी जोड़ा जा सकता है, जिनमें मौजूदा निर्भर कोड को बदलने की कोई आवश्यकता नहीं है।

उदाहरण के लिए, एक वर्ग Carऔर दो उपवर्गों पर विचार करें Volvoऔर Mazda

यदि आपका कोड a पर निर्भर करता है Car, तो यह रनटाइम के दौरान Volvoया तो उपयोग कर सकता Mazdaहै। इसके अलावा बाद में अतिरिक्त उपवर्गों पर निर्भर कोड को बदलने की आवश्यकता नहीं के साथ जोड़ा जा सकता है।

इसके अलावा, Car- जो एक अमूर्त है - की तुलना में बदलने की संभावना कम है Volvoया Mazda। कारें आमतौर पर काफी समय से समान हैं, लेकिन वोल्वोस और मजदास के बदलने की संभावना अधिक है। यानी अमूर्त ठोस प्रकारों की तुलना में अधिक स्थिर हैं।

यह सब यह दिखाने के लिए था कि मैं समझता हूं कि ढीली युग्मन क्या है और यह कैसे अमूर्तता के आधार पर प्राप्त किया जाता है और सहमति पर नहीं। (अगर मैंने कुछ गलत लिखा है तो कृपया कहें)।

जो मुझे समझ नहीं आ रहा है वह यह है:

सार सुपरक्लास या इंटरफेस हो सकते हैं।

यदि हां, तो ढीले युग्मन की अनुमति देने की उनकी क्षमता के लिए इंटरफेस की विशेष रूप से प्रशंसा क्यों की जाती है? मैं नहीं देखता कि यह सुपरक्लास का उपयोग करने से अलग कैसे है।

केवल अंतर जो मैं देख रहा हूं वे हैं: 1- अंतर केवल एकल वंशानुक्रम द्वारा सीमित नहीं हैं, लेकिन ढीलेपन के विषय के साथ ऐसा करने के लिए बहुत कुछ नहीं है। 2- इंटरफेस अधिक 'अमूर्त' होते हैं क्योंकि उनके पास कोई कार्यान्वयन तर्क नहीं होता है। लेकिन फिर भी, मैं यह नहीं देखता कि इतना बड़ा फर्क क्यों पड़ता है।

कृपया मुझे समझाएं कि ढीले युग्मन की अनुमति देने में इंटरफेस को महान क्यों कहा जाता है, जबकि सरल सुपरक्लेसेस नहीं हैं।


3
अधिकांश भाषाएँ (उदाहरण के लिए Java, C #) जिनमें "इंटरफेस" हैं, केवल एकल वंशानुक्रम का समर्थन करती हैं। जैसा कि प्रत्येक वर्ग में केवल एक तत्काल सुपरक्लास हो सकता है, (एब्स्ट्रैक्ट) सुपरक्लास एक ऑब्जेक्ट के लिए कई सार का समर्थन करने के लिए बहुत सीमित हैं। एक आधुनिक विकल्प के लिए लक्षण (जैसे स्काला या पर्ल की भूमिका ) की जांच करें जो कई अंतर्निहितता के साथ " हीरे की समस्या " से बचा जाता है ।
अमोन

@ वामन तो आप कह रहे हैं कि ढीले युग्मन को प्राप्त करने की कोशिश करने पर अमूर्त वर्गों पर इंटरफेस का लाभ क्या उन्हें एकल विरासत द्वारा सीमित नहीं किया जा रहा है?
अवीव कोहन

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

2
ऐसा लगता है कि @amon सही रास्ते पर है, मुझे यह पोस्ट मिली जहां यह कहा जाता है कि: interfaces are essential for single-inheritance languages like Java and C# because that's the only way in which you can aggregate different behaviors into a single class(जो मुझे C ++ के साथ तुलना करने के लिए छोड़ता है , जहां इंटरफेस केवल शुद्ध आभासी कार्यों के साथ कक्षाएं हैं)।
पेस्ट्री

कृपया बताएं कि कौन कहता है कि सुपरक्लास खराब हैं।
तुलसी कोर्डोवा

जवाबों:


11

शब्दावली: मैं भाषा के निर्माण interfaceको इंटरफेस के रूप में संदर्भित करूंगा , और सतह के रूप में एक प्रकार या वस्तु के इंटरफेस के लिए (एक बेहतर सामग्री की कमी के लिए)।

ढीली युग्मन को एक ठोस प्रकार के बजाय एक अमूर्त पर निर्भर करते हुए प्राप्त किया जा सकता है।

सही बात।

यह दो मुख्य कारणों के लिए ढीली युग्मन की अनुमति देता है: 1 - सार ठोस प्रकार की तुलना में कम होने की संभावना है, जिसका अर्थ है कि आश्रित कोड के टूटने की संभावना कम है। 2 - विभिन्न ठोस प्रकारों का उपयोग रनटाइम पर किया जा सकता है, क्योंकि वे सभी अमूर्त रूप में फिट होते हैं। नए कंक्रीट प्रकारों को बाद में भी जोड़ा जा सकता है, जिनमें मौजूदा निर्भर कोड को बदलने की कोई आवश्यकता नहीं है।

बिल्कुल सही नहीं है। वर्तमान भाषाएं आमतौर पर यह अनुमान नहीं लगाती हैं कि एक अमूर्त बदल जाएगा (हालांकि इसे संभालने के लिए कुछ डिज़ाइन पैटर्न हैं)। सामान्य चीजों से अलग-अलग बारीकियों को अमूर्त करना है। यह आमतौर पर अमूर्त की कुछ परत द्वारा किया जाता है । इस परत को कोड तोड़ने के बिना कुछ अन्य बारीकियों में बदला जा सकता है जो इस अमूर्त पर बनाता है - ढीली युग्मन प्राप्त की जाती है। नॉन- sortओओपी उदाहरण: एक रूटीन को क्विकॉर्ट से संस्करण 1 में टिम सॉर्ट में बदला जा सकता है। संस्करण 2. कोड जो केवल छंटे जा रहे परिणाम पर निर्भर करता है (यानी sortएब्सट्रैक्शन पर बनाता है ) इसलिए वास्तविक छँटाई के कार्यान्वयन से अलग कर दिया जाता है।

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

एक वस्तु कई सार का समर्थन कैसे कर सकती है?

सी ++ में इंटरफेस नहीं है, लेकिन इसमें कई विरासत, आभासी तरीके और सार कक्षाएं हैं। एक अमूर्तता को तब एक सार वर्ग (यानी एक ऐसा वर्ग जो तत्काल नहीं किया जा सकता) के रूप में परिभाषित किया जा सकता है जो घोषित करता है, लेकिन आभासी तरीकों को परिभाषित नहीं करता है। एक अमूर्तता की बारीकियों को लागू करने वाली कक्षाएं फिर उस सार वर्ग से विरासत में मिल सकती हैं और आवश्यक आभासी तरीकों को लागू कर सकती हैं।

यहाँ समस्या यह है कि एकाधिक वंशानुक्रम हीरे की समस्या को जन्म दे सकता है , जहाँ एक विधि कार्यान्वयन के लिए कक्षाओं को खोजा जाता है (MRO: विधि संकल्प आदेश) "विरोधाभासों" को जन्म दे सकता है। इसके लिए दो प्रतिक्रियाएँ हैं:

  1. एक समझदार आदेश को परिभाषित करें और उन आदेशों को अस्वीकार करें जिन्हें समझदारी से रैखिक नहीं किया जा सकता है। सी 3 एमआरओ काफी समझदार है और अच्छी तरह से काम करता है। यह 1996 में प्रकाशित हुआ था।

  2. आसान रास्ता अपनाएं और कई तरह की विरासत को अस्वीकार करें।

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

परिणाम यह है कि एमआरओ स्पष्ट है (बस प्रत्येक सुपरक्लास को क्रम में देखें), और यह कि हमारी वस्तु में किसी भी संख्या के लिए कई सतहें हो सकती हैं।

यह बल्कि असंतोषजनक है, क्योंकि अक्सर व्यवहार का एक हिस्सा सतह का एक हिस्सा है। एक Comparableइंटरफ़ेस पर विचार करें:

interface Comparable<T> {
    public int cmp(T that);
    public boolean lt(T that);  // less than
    public boolean le(T that);  // less than or equal
    public boolean eq(T that);  // equal
    public boolean ne(T that);  // not equal
    public boolean ge(T that);  // greater than or equal
    public boolean gt(T that);  // greater than
}

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

यह एक विशेषता संरचना को परिभाषित करने के द्वारा किया जाता है ताकि लक्षण वास्तव में MRO में भाग लेने से समाप्त न हों - इसके बजाय परिभाषित तरीके कार्यान्वयन वर्ग में बनाए जाते हैं।

Comparableइंटरफेस के रूप में स्काला में व्यक्त किया जा सकता है

trait Comparable[T] {
    def cmp(that: T): Int
    def lt(that: T): Boolean = this.cmp(that) <  0
    def le(that: T): Boolean = this.cmp(that) <= 0
    ...
}

जब कोई वर्ग उस विशेषता का उपयोग करता है, तो अन्य विधियाँ वर्ग परिभाषा में जुड़ जाती हैं:

// "extends" isn't different from Java's "implements" in this case
case class Inty(val x: Int) extends Comparable[Inty] {
    override def cmp(that: Inty) = this.x - that.x
    // lt etc. get added automatically
}

तो Inty(4) cmp Inty(6)होगा -2और Inty(4) lt Inty(6)होगा true

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

दुर्भाग्य से, लक्षण एक हालिया आविष्कार (2002) हैं, और इस प्रकार बड़ी मुख्यधारा की भाषाओं में काफी दुर्लभ हैं।


अच्छा जवाब है, लेकिन मैं यह जोड़ूंगा कि एकल-विरासत वाली भाषाएं रचना के साथ इंटरफेस का उपयोग करते हुए कई विरासत को निकाल सकती हैं

4

जो मुझे समझ नहीं आ रहा है वह यह है:

सार सुपरक्लास या इंटरफेस हो सकते हैं।

यदि हां, तो ढीले युग्मन की अनुमति देने की उनकी क्षमता के लिए इंटरफेस की विशेष रूप से प्रशंसा क्यों की जाती है? मैं नहीं देखता कि यह सुपरक्लास का उपयोग करने से अलग कैसे है।

सबसे पहले, घटाव और अमूर्त दो अलग-अलग चीजें हैं। केवल उप-प्रकार का मतलब है कि मैं एक प्रकार के मूल्यों को दूसरे प्रकार के मूल्यों के लिए स्थानापन्न कर सकता हूं - न तो प्रकार को सार होने की आवश्यकता है।

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

एक इंटरफ़ेस को लागू करने से आपको इंटरफ़ेस के अलावा कुछ भी नहीं मिलता है, जिसमें कोई व्यवहार नहीं है।


जवाब के लिए धन्यवाद। यह देखने के लिए कि क्या मुझे समझ में आता है: जब आप ए नाम की एक वस्तु को बी नाम के एब्स्ट्रैक्शन के बजाय बी नाम के एक अमूर्त पर निर्भर करना चाहते हैं, तो अक्सर बी के लिए बेहतर होगा कि सी द्वारा लागू किए गए इंटरफ़ेस के बजाय सुपरक्लॉस द्वारा बढ़ाया जाए। C. इसका कारण यह है: C उप-बी को कसकर जोड़ देता है C से B. यदि B बदल जाता है - C बदलता है। हालाँकि C लागू करने वाला B (B एक इंटरफ़ेस है) B से C को जोड़े नहीं है: B केवल उन विधियों की एक सूची है जिन्हें C को लागू करना चाहिए, इस प्रकार कोई तंग युग्मन नहीं है। हालांकि ऑब्जेक्ट ए (आश्रित) के बारे में, यह कोई फर्क नहीं पड़ता कि बी एक वर्ग या इंटरफ़ेस है।
अवीव कोहन

सही बात? .....।
अवीव कोहन

आप किसी इंटरफ़ेस को किसी चीज़ के साथ युग्मित करने पर विचार क्यों करेंगे?
माइकल शॉ

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

@ प्रश्न आपके विचार की लाइन ज्यादातर सही है, लेकिन फिर से, अमूर्त और घटाव दो अलग चीजें हैं। जब आप कहते हैं कि you want an object named A to depend on an abstraction named B instead of a concrete implementation of that abstraction named Cआप मान रहे हैं कि कक्षाएं किसी तरह सार नहीं हैं। एक अमूर्त एक ऐसी चीज है जो कार्यान्वयन विवरण को छुपाता है, इसलिए निजी फ़ील्ड के साथ एक वर्ग समान सार्वजनिक विधियों के साथ एक इंटरफ़ेस के रूप में सार है।
डोभाल

1

माता-पिता और बच्चे की कक्षाओं के बीच युग्मन होता है, क्योंकि बच्चा माता-पिता पर निर्भर करता है।

कहो कि हमारे पास एक वर्ग ए है, और वर्ग बी को उससे विरासत में मिला है। अगर हम क्लास ए में जाते हैं और चीजों को बदलते हैं, तो क्लास बी भी बदल जाता है।

कहें कि हमारे पास एक इंटरफ़ेस I है, और क्लास बी इसे लागू करता है। यदि हम इंटरफ़ेस I को बदलते हैं, तो हालांकि क्लास बी इसे लागू नहीं कर सकता है, क्लास बी अपरिवर्तित है।


मैं उत्सुक हूं कि क्या डाउनवॉटर्स के पास एक कारण था, या बस एक बुरे दिन थे।
माइकल शॉ

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

@ जॉनघन: प्रतिक्रिया के लिए धन्यवाद। स्पष्टता के लिए संपादित।
माइकल शॉ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.