Interfaces बहुरूपित भाषाओं को बहुरूपता का समर्थन करने की अनुमति देते हैं। ऑब्जेक्ट ओरिएंटेड प्यूरिस्ट का आग्रह होगा कि एक भाषा पूरी तरह से चित्रित ऑब्जेक्ट ओरिएंटेड भाषा होने के लिए विरासत, एनकैप्सुलेशन, प्रतिरूपकता और बहुरूपता प्रदान करे। डायनामिक रूप से टाइप किए गए - या बतख टाइप किए गए - भाषाएं (जैसे स्मॉलटाकल), पॉलीमॉर्फिज़्म तुच्छ है; हालाँकि, वैधानिक रूप से टाइप की गई भाषाओं में (जैसे जावा या C #), बहुरूपता तुच्छता से बहुत दूर है (वास्तव में, सतह पर यह मजबूत टाइपिंग की धारणा के साथ है।)
मुझे प्रदर्शित करें:
डायनामिक रूप से टाइप की गई (या डक टाइप की गई) भाषा (जैसे स्मॉलटाकल), सभी चर वस्तुओं के संदर्भ में हैं (कुछ कम नहीं और कुछ अधिक नहीं।) इसलिए, स्मालटाक में, मैं यह कर सकता हूं:
|anAnimal|
anAnimal := Pig new.
anAnimal makeNoise.
anAnimal := Cow new.
anAnimal makeNoise.
वह कोड:
- एक स्थानीय चर घोषित किया जाता है जिसे अनिमल कहा जाता है (ध्यान दें कि हम चर के प्रकार को निर्दिष्ट नहीं करते हैं - सभी चर एक वस्तु के संदर्भ हैं, कोई अधिक और कोई कम नहीं।)
- "पिग" नामक वर्ग का एक नया उदाहरण बनाता है
- चर के उस नए उदाहरण को चर पर निरुपित करता है।
makeNoise
सुअर को संदेश भेजता है ।
- एक गाय का उपयोग करके पूरी बात दोहराता है, लेकिन इसे सुअर के समान सटीक चर में असाइन करना।
एक ही जावा कोड कुछ इस तरह दिखाई देगा (यह धारणा बनाते हुए कि बतख और गाय पशु के उपवर्ग हैं:
Animal anAnimal = new Pig();
duck.makeNoise();
anAnimal = new Cow();
cow.makeNoise();
यह सब अच्छी तरह से और अच्छा है, जब तक हम क्लास वेजीटेबल का परिचय नहीं देते। सब्जियों में जानवरों के समान व्यवहार होता है, लेकिन सभी नहीं। उदाहरण के लिए, पशु और वनस्पति दोनों ही विकसित करने में सक्षम हो सकते हैं, लेकिन स्पष्ट रूप से सब्जियां शोर नहीं करती हैं और जानवरों को काटा नहीं जा सकता है।
स्मालटाक में, हम इसे लिख सकते हैं:
|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.
aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.
यह स्मॉलटाकल में पूरी तरह से अच्छी तरह से काम करता है क्योंकि यह डक-टाइप्ड है (यदि यह बत्तख की तरह चलता है, और बत्तख की तरह चुटकी लेता है - यह बत्तख है।) इस मामले में, जब किसी वस्तु को संदेश भेजा जाता है, तो एक लुकअप किया जाता है। रिसीवर की विधि सूची, और यदि एक मिलान विधि पाई जाती है, तो उसे कहा जाता है। यदि नहीं, तो किसी प्रकार के NoSuchMethodError अपवाद को फेंक दिया जाता है - लेकिन यह सब रनटाइम पर किया जाता है।
लेकिन जावा में, एक स्टेटिकली टाइप की गई भाषा, हम अपने वेरिएबल को किस प्रकार असाइन कर सकते हैं? मकई को वेजिटेबल से उगने की जरूरत है, बढ़ने में सहायता करने के लिए, लेकिन पशु से विरासत में नहीं मिल सकता है, क्योंकि यह शोर नहीं करता है। गाय को मेकओनिस का समर्थन करने के लिए पशु से विरासत में प्राप्त करने की आवश्यकता है, लेकिन सब्जी से विरासत में नहीं मिल सकता है क्योंकि इसे फसल को लागू नहीं करना चाहिए। ऐसा लगता है कि हमें एक से अधिक विरासत की आवश्यकता है - एक से अधिक वर्ग से विरासत में लेने की क्षमता। लेकिन यह एक बहुत ही कठिन भाषा की विशेषता है क्योंकि सभी किनारे के मामले पॉप अप करते हैं (एक से अधिक समानांतर सुपरक्लास एक ही विधि को लागू करने से क्या होता है ?, आदि)
आने वाले इंटरफेस के साथ ...
यदि हम पशु और वनस्पति वर्ग बनाते हैं, तो प्रत्येक को विकसित करने के साथ, हम घोषणा कर सकते हैं कि हमारी गाय पशु है और हमारी मकई सब्जी है। हम यह भी घोषित कर सकते हैं कि पशु और वनस्पति दोनों ही बढ़ने योग्य हैं। इससे हमें सब कुछ बढ़ने के लिए लिखना पड़ता है:
List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());
for(Growable g : list) {
g.grow();
}
और यह हमें ऐसा करने की अनुमति देता है, जिससे पशु शोर कर सके:
List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
a.makeNoise();
}
डक-टाइप की गई भाषा का लाभ यह है कि आपको वास्तव में अच्छा बहुरूपता मिलता है: व्यवहार प्रदान करने के लिए सभी वर्ग को विधि प्रदान करनी होती है। जब तक हर कोई अच्छा खेलता है, और केवल उन संदेशों को भेजता है जो परिभाषित तरीकों से मेल खाते हैं, सब अच्छा है। नकारात्मक पक्ष यह है कि रनटाइम तक नीचे की तरह की त्रुटि नहीं पकड़ी गई है:
|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.
सांख्यिकीय रूप से टाइप की गई भाषाएं "अनुबंध द्वारा प्रोग्रामिंग" को बहुत बेहतर प्रदान करती हैं, क्योंकि वे संकलन-समय पर नीचे दो प्रकार की त्रुटि पकड़ लेंगे:
// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();
farmObject makeNoise();
-
// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest();
इसलिए .... संक्षेप में:
इंटरफ़ेस कार्यान्वयन आपको यह निर्दिष्ट करने की अनुमति देता है कि ऑब्जेक्ट किस प्रकार की चीजें कर सकते हैं (इंटरैक्शन) और क्लास इनहेरिटेंस आपको यह निर्दिष्ट करने देता है कि चीजों को कैसे किया जाना चाहिए (कार्यान्वयन)।
संकलक प्रकार की जाँच के त्याग के बिना, इंटरफेस हमें "सच्चे" बहुरूपता के कई लाभ देते हैं।