बहुरूपता के विभिन्न प्रकार होते हैं, ब्याज में से एक आमतौर पर रनटाइम बहुरूपता / गतिशील प्रेषण है।
रनटाइम बहुरूपता का एक बहुत ही उच्च-स्तरीय वर्णन यह है कि एक विधि कॉल रनटाइम प्रकार के तर्कों के आधार पर अलग-अलग चीजें करता है: एक विधि कॉल को हल करने के लिए ऑब्जेक्ट स्वयं जिम्मेदार है। यह बड़ी मात्रा में लचीलेपन की अनुमति देता है।
इस लचीलेपन का उपयोग करने के सबसे सामान्य तरीकों में से एक निर्भरता इंजेक्शन के लिए है , उदाहरण के लिए , ताकि मैं विभिन्न कार्यान्वयन के बीच स्विच कर सकूं या परीक्षण के लिए नकली वस्तुओं को इंजेक्ट कर सकूं। अगर मुझे पहले से पता है कि सीमित संख्या में संभव विकल्प होंगे तो मैं उन्हें सशर्त के साथ हार्डकोड करने की कोशिश कर सकता हूं, जैसे:
void foo() {
if (isTesting) {
... // do mock stuff
} else {
... // do normal stuff
}
}
यह कोड का पालन करना कठिन बनाता है। विकल्प यह है कि उस फू-ऑपरेशन के लिए एक इंटरफ़ेस शुरू करना और एक सामान्य कार्यान्वयन और उस इंटरफ़ेस का एक नकली कार्यान्वयन लिखना, और रनटाइम में वांछित कार्यान्वयन के लिए "इंजेक्शन" करना। "निर्भरता इंजेक्शन" एक तर्क के रूप में "सही वस्तु को पारित करने" के लिए एक जटिल शब्द है।
एक वास्तविक दुनिया के उदाहरण के रूप में, मैं वर्तमान में एक तरह की मशीन-सीखने की समस्या पर काम कर रहा हूं। मेरे पास एक एल्गोरिथ्म है जिसमें एक भविष्यवाणी मॉडल की आवश्यकता होती है। लेकिन मैं अलग-अलग मशीन लर्निंग एल्गोरिदम आज़माना चाहता हूं। इसलिए मैंने एक इंटरफ़ेस परिभाषित किया। मुझे अपने भविष्यवाणी मॉडल से क्या चाहिए? कुछ इनपुट नमूने, भविष्यवाणी और इसकी त्रुटियों को देखते हुए:
interface Model {
def predict(sample) -> (prediction: float, std: float);
}
मेरा एल्गोरिथ्म एक कारखाना फ़ंक्शन लेता है जो एक मॉडल को प्रशिक्षित करता है:
def my_algorithm(..., train_model: (observations) -> Model, ...) {
...
Model model = train_model(observations);
...
y, std = model.predict(x)
...
}
अब मेरे पास मॉडल इंटरफ़ेस के विभिन्न कार्यान्वयन हैं और उन्हें एक दूसरे के खिलाफ बेंचमार्क कर सकते हैं। इन कार्यान्वयनों में से एक वास्तव में दो अन्य मॉडल लेता है और उन्हें एक बढ़ाया मॉडल में जोड़ता है। तो इस इंटरफ़ेस के लिए धन्यवाद:
- मेरे एल्गोरिथ्म को पहले से विशिष्ट मॉडल के बारे में जानने की आवश्यकता नहीं है,
- मैं आसानी से मॉडल स्वैप कर सकता हूं, और
- मेरे पास अपने मॉडल को लागू करने में बहुत लचीलापन है।
जीयूआई में बहुरूपता का एक क्लासिक उपयोग मामला है। GUI ढांचे में जैसे जावा AWT / स्विंग / ... अलग-अलग घटक होते हैं । घटक इंटरफ़ेस / बेस क्लास स्क्रीन पर खुद को पेंट करने या माउस क्लिक पर प्रतिक्रिया करने जैसी क्रियाओं का वर्णन करता है। कई घटक कंटेनर होते हैं जो उप-घटकों का प्रबंधन करते हैं। ऐसे कंटेनर को कैसे आकर्षित किया जा सकता है?
void paint(Graphics g) {
super.paint(g);
for (Component child : this.subComponents)
child.paint(g);
}
यहां, कंटेनर को अग्रिम में सटीक प्रकार के सब-कॉम्प्लेक्टर्स के बारे में जानने की आवश्यकता नहीं है - जब तक वे Component
इंटरफ़ेस के अनुरूप होते हैं , कंटेनर बस पॉलीमॉर्फिक paint()
विधि को कॉल कर सकता है । यह मुझे मनमाने ढंग से नए घटकों के साथ AWT वर्ग पदानुक्रम का विस्तार करने की स्वतंत्रता देता है।
सॉफ्टवेयर विकास के दौरान कई आवर्ती समस्याएं हैं जिन्हें एक तकनीक के रूप में बहुरूपता को लागू करके हल किया जा सकता है। ये आवर्ती समस्या-समाधान जोड़े को डिज़ाइन पैटर्न कहा जाता है , और उनमें से कुछ उसी नाम की पुस्तक में एकत्र किए जाते हैं। उस पुस्तक के संदर्भ में, मेरा इंजेक्टेड मशीन लर्निंग मॉडल एक ऐसी रणनीति होगी जिसका उपयोग मैं "एल्गोरिदम के एक परिवार को परिभाषित करने, प्रत्येक को एन्कैप्सुलेट करने और उन्हें विनिमेय बनाने" के लिए करता हूं। जावा-एडब्ल्यूटी उदाहरण जहां एक घटक में उप-घटक शामिल हो सकते हैं, एक समग्र का एक उदाहरण है ।
लेकिन हर डिज़ाइन को पॉलीमॉर्फिज़्म (यूनिट टेस्टिंग के लिए निर्भरता इंजेक्शन को सक्षम करने से परे) का उपयोग करने की आवश्यकता नहीं है, जो वास्तव में अच्छा उपयोग मामला है)। अधिकांश समस्याएं अन्यथा बहुत स्थैतिक हैं। एक परिणाम के रूप में, वर्गों और विधियों का उपयोग अक्सर बहुरूपता के लिए नहीं किया जाता है, लेकिन बस सुविधाजनक नामस्थान के रूप में और सुंदर विधि कॉल सिंटैक्स के लिए किया जाता है। जैसे कई डेवलपर्स account.getBalance()
एक बड़े पैमाने पर समकक्ष फ़ंक्शन कॉल की तरह विधि कॉल पसंद करते हैं Account_getBalance(account)
। यह पूरी तरह से ठीक दृष्टिकोण है, यह सिर्फ इतना है कि कई "विधि" कॉल का बहुरूपता से कोई लेना-देना नहीं है।