शब्दावली: मैं भाषा के निर्माण interface
को इंटरफेस के रूप में संदर्भित करूंगा , और सतह के रूप में एक प्रकार या वस्तु के इंटरफेस के लिए (एक बेहतर सामग्री की कमी के लिए)।
ढीली युग्मन को एक ठोस प्रकार के बजाय एक अमूर्त पर निर्भर करते हुए प्राप्त किया जा सकता है।
सही बात।
यह दो मुख्य कारणों के लिए ढीली युग्मन की अनुमति देता है: 1 - सार ठोस प्रकार की तुलना में कम होने की संभावना है, जिसका अर्थ है कि आश्रित कोड के टूटने की संभावना कम है। 2 - विभिन्न ठोस प्रकारों का उपयोग रनटाइम पर किया जा सकता है, क्योंकि वे सभी अमूर्त रूप में फिट होते हैं। नए कंक्रीट प्रकारों को बाद में भी जोड़ा जा सकता है, जिनमें मौजूदा निर्भर कोड को बदलने की कोई आवश्यकता नहीं है।
बिल्कुल सही नहीं है। वर्तमान भाषाएं आमतौर पर यह अनुमान नहीं लगाती हैं कि एक अमूर्त बदल जाएगा (हालांकि इसे संभालने के लिए कुछ डिज़ाइन पैटर्न हैं)। सामान्य चीजों से अलग-अलग बारीकियों को अमूर्त करना है। यह आमतौर पर अमूर्त की कुछ परत द्वारा किया जाता है । इस परत को कोड तोड़ने के बिना कुछ अन्य बारीकियों में बदला जा सकता है जो इस अमूर्त पर बनाता है - ढीली युग्मन प्राप्त की जाती है। नॉन- sort
ओओपी उदाहरण: एक रूटीन को क्विकॉर्ट से संस्करण 1 में टिम सॉर्ट में बदला जा सकता है। संस्करण 2. कोड जो केवल छंटे जा रहे परिणाम पर निर्भर करता है (यानी sort
एब्सट्रैक्शन पर बनाता है ) इसलिए वास्तविक छँटाई के कार्यान्वयन से अलग कर दिया जाता है।
जिसे मैंने ऊपर की सतह कहा है, वह अमूर्तता का सामान्य हिस्सा है। यह अब OOP में होता है कि एक वस्तु को कभी-कभी कई सार का समर्थन करना चाहिए। एक नहीं-काफी इष्टतम उदाहरण: जावा java.util.LinkedList
दोनों List
इंटरफ़ेस का समर्थन करता है जो "ऑर्डर किए गए, इंडेक्सेबल कलेक्शन" एब्सट्रैक्शन के बारे में है, और Queue
इंटरफ़ेस का समर्थन करता है जो (मोटे तौर पर) "एफआईएफओ" एब्सट्रैक्शन के बारे में है।
एक वस्तु कई सार का समर्थन कैसे कर सकती है?
सी ++ में इंटरफेस नहीं है, लेकिन इसमें कई विरासत, आभासी तरीके और सार कक्षाएं हैं। एक अमूर्तता को तब एक सार वर्ग (यानी एक ऐसा वर्ग जो तत्काल नहीं किया जा सकता) के रूप में परिभाषित किया जा सकता है जो घोषित करता है, लेकिन आभासी तरीकों को परिभाषित नहीं करता है। एक अमूर्तता की बारीकियों को लागू करने वाली कक्षाएं फिर उस सार वर्ग से विरासत में मिल सकती हैं और आवश्यक आभासी तरीकों को लागू कर सकती हैं।
यहाँ समस्या यह है कि एकाधिक वंशानुक्रम हीरे की समस्या को जन्म दे सकता है , जहाँ एक विधि कार्यान्वयन के लिए कक्षाओं को खोजा जाता है (MRO: विधि संकल्प आदेश) "विरोधाभासों" को जन्म दे सकता है। इसके लिए दो प्रतिक्रियाएँ हैं:
एक समझदार आदेश को परिभाषित करें और उन आदेशों को अस्वीकार करें जिन्हें समझदारी से रैखिक नहीं किया जा सकता है। सी 3 एमआरओ काफी समझदार है और अच्छी तरह से काम करता है। यह 1996 में प्रकाशित हुआ था।
आसान रास्ता अपनाएं और कई तरह की विरासत को अस्वीकार करें।
जावा ने बाद का विकल्प लिया और एकल व्यवहार विरासत को चुना। हालाँकि, हमें अभी भी कई सार का समर्थन करने के लिए किसी वस्तु की क्षमता की आवश्यकता है। इसलिए, इंटरफेस का उपयोग करना पड़ता है जो केवल परिभाषाओं का समर्थन नहीं करते हैं।
परिणाम यह है कि एमआरओ स्पष्ट है (बस प्रत्येक सुपरक्लास को क्रम में देखें), और यह कि हमारी वस्तु में किसी भी संख्या के लिए कई सतहें हो सकती हैं।
यह बल्कि असंतोषजनक है, क्योंकि अक्सर व्यवहार का एक हिस्सा सतह का एक हिस्सा है। एक 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) हैं, और इस प्रकार बड़ी मुख्यधारा की भाषाओं में काफी दुर्लभ हैं।