जब विधि अधिभार उपयुक्त है?


10

मान लीजिए मैं एक मौजूदा, यथोचित बड़ी प्रणाली पर काम कर रहा हूं। मेरे पास एक ऑब्जेक्ट है, myObjectक्लास का MyClass(उदाहरण के लिए, मान लीजिए मैं जावा में काम कर रहा हूं)। myObjectएक रचना है Collection, जिसमें कहा गया है, एक Listऔर अन्य वस्तुएं जो (मुझे लगता है) अप्रासंगिक हैं। इसमें प्रतिनिधि विधियाँ शामिल हैं, जो सिर्फ इसके तरीकों पर कॉल करने के लिए सेवा प्रदान करती Listहैं, ताकि Listयह सुनिश्चित हो सके कि इसे उजागर नहीं किया गया है (क्षमा करें यदि मुझे मेरी शब्दावली गलत लगी है)।

मान लें कि यह Listएक है List<String>, लेकिन किसी कारण से, मुख्य उपयोग विधि कक्षा के लिए एक मुखौटा विधि है SomeOtherClass। यदि मैं अपने में एक नया मूल्य जोड़ी बनाना चाहता था List, तो मेरे पास SomeOtherClassकॉल की गई वस्तु होगी someObject। मैं फोन करूंगा myObject.insert(someObject)और insertविधि के अंदर कुछ जादू होगा जो कि एक Stringमें डालने के लिए पुनः प्राप्त होगा List<String>

अब मान लें कि मुझे केवल एक Stringमूल्य मिला है , और कोई SomeOtherClassऑब्जेक्ट डालने के लिए नहीं । यह मानते हुए कि मैं इस insertपद्धति को संशोधित नहीं कर सकता क्योंकि यह इस प्रणाली में सब कुछ तोड़ देगा। तो फिर क्या मुझे इस insertविधि को ओवरलोड करना चाहिए ? या मुझे SomeOtherClassहर बार जब मैं कॉल करना चाहता हूं तो मुझे एक नई वस्तु बनानी चाहिए insert?

मुझे लगता है कि अगर मैंने इसे ओवरलोड किया, तो यह कुछ इस तरह दिखेगा ...

public void insert(String s) {
    ...
}

public void insert(SomeOtherObject obj) {
    this.insert(obj.magicStringMethod());
}

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

क्या यह एक विधि को अधिभारित करने के लिए एक उपयुक्त स्थान होगा? यदि नहीं, तो मुझे एक विधि को कब लोड करना चाहिए?


जावा की मानें, तो क्या आपने इस समस्या को हल करने के लिए जेनरिक का उपयोग किया है? मुझे लगता है कि मैं वास्तव में पूछ रहा हूं कि स्ट्रिंग वास्तव में क्या दर्शाता है? अगर यह वास्तव में एक वास्तविक डोमेन ऑब्जेक्ट का प्रतिनिधित्व करता है, तो इस मुद्दे को हल करने का एक और संभावित तरीका है
मार्टिग्न वर्बर्ग

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

मेरा सुझाव है कि जब आप कर सकते हैं तब आप ओवरलोडिंग से दूर रहे। यह कभी-कभी भ्रम पैदा करता है। डिजाइन समय पर तथाकथित विधि के बारे में निश्चित होना सबसे अच्छा है। इसे देखें: programmers.stackexchange.com/questions/132369/…
NoChance

जवाबों:


7

जब आप विभिन्न प्रकारों का समर्थन करना चाहते हैं तो आप ओवरलोड करते हैं:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

या विभिन्न पैरामीटर सूचियों का उपयोग करके एक प्रगतिशील इंटरफ़ेस का समर्थन करने के लिए:

public overload void MyOtherMethod()
{
    this.MyOtherMethod(DefaultValue);
}

public overload void MyOtherMethod(int value)
{
    this.MyOtherMethod(value, DefaultOtherValue);
}

public overload void MyOtherMethod(int value, bool otherValue)
{
    ...
}

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


7

मैं यह कहूंगा कि जब दोनों विधियां शब्दार्थ के समकक्ष हों तो ओवरलोडिंग उचित है। ड्यूकफॉगमिंग के उदाहरणों से चोरी करने के लिए:

ये उचित रूप से ओवरलोड हैं:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a+b;
}

ये नहीं हैं:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a-b;
}

यह एक चरम उदाहरण है (यदि आपने इसे नहीं पकड़ा था, तो अंतिम विधि वास्तव में जोड़ के बजाय घट जाती है), लेकिन विचार यह है कि यदि आपके पास एक ही नाम के साथ कक्षा में कई विधियां हैं, तो उन्हें लगातार व्यवहार करना चाहिए।

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


1
जवाब के लिए धन्यवाद। मैंने किसी और वरिष्ठ से पूछा, लेकिन चूंकि कोड कुछ दिलचस्प स्थिति में है, उनका समाधान एक ऐसा था जिसके बारे में मुझे यकीन नहीं था, लेकिन फिर भी इसे लागू किया गया (यह ओवरलोडिंग नहीं था)।
ब्लाहमन

5

अनिवार्य रूप से विधि के मापदंडों को निर्धारित करना है कि विधि कैसे व्यवहार करेगी।

एक त्वरित उदाहरण होगा:

class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    //...
}

यदि आप विधि योग (ए, बी) पूर्णांकों के एक जोड़े को पास करते हैं, तो यह पता है कि इसे पहले कार्यान्वयन को कॉल करना चाहिए, क्योंकि विधि कॉल विधि हस्ताक्षर के साथ मेल खाता है (यानी डबल योग (डबल, डबल) अगर आप देते हैं तो काम नहीं करेगा) योग विधि दो पूर्णांक)।

कॉल का हस्ताक्षर उपलब्ध कार्यान्वयन से मेल खाना चाहिए, इसलिए योग (स्ट्रिंग, स्ट्रिंग) को कॉल करने का प्रयास तब तक काम नहीं करेगा जब तक कि आपके पास यह न हो:

class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    public string sum(String a, String b){
        return "" + (Double.parseDouble(a) + Double.parseDouble(b));
    }
    //...
}

tl; dr: कक्षा को उसी नाम के साथ जो भी पैरामीटर देते हैं, उसके अनुसार सही पद्धति को संभालना है।

विरासत में मिलने पर इसे ओवरराइडिंग कहा जाता है

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

कल्पना कीजिए कि आपके पास class Robotऔर एक विधि है fireAtTarget(Target target)... जिसे fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);एक के बाद एक कॉल किया जाता है । आप भी एक संग्रह चाहते हैं जिसका नाम robot_army है जिसमें आप केवल क्लास रोबोट की वस्तुओं को जोड़ सकते हैं। रोबोट अपने fireWeaponX()तरीकों से डिफ़ॉल्ट रूप से मशीनगन फायर करता है।

तो फिर तुम करना चाहते हैं class LazorRobotऔर class MissileRobotआप रोबोट को फिर से लागू करते हैं ?, कोई, बस LazorRobot और MissileRobot इनहेरिट रोबोट है, और, ओवरलोड प्रत्येक fireWeaponX()उपयोग lazorz या मिसाइलों के लिए विधि और आप, विभिन्न हथियारों के साथ एक ही व्यवहार होगा reimplement बिना बाकी विधियाँ।

tl; dr: विधि के व्यवहार को इंटरफ़ेस को तोड़ने के बिना वर्ग पर निर्भर करता है (Robot_army केवल रोबोट को स्वीकार करता है, लेकिन रोबोट को प्राप्त करने वाले किसी भी वर्ग को विस्तार से स्वीकार करता है)।


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

डेरप, कैफीन मुझे इस बार मिला = पी, दूसरे भाग को पहले और सामान्य हित के लिए दूसरे के रूप में छोड़ दिया। सुधारों के लिए धन्यवाद।
ड्यूकफैगिंग

यदि मैं आपके उत्तर को सही ढंग से समझता हूं, तो मुझे केवल तभी ओवरलोडिंग करना चाहिए जब मापदंडों को देखते हुए मुझे व्यवहार के बीच के अंतरों का पता लगाने की अनुमति होगी, sum(String, String)और sum(int, int)?
ब्लाहमन

जब आप विभिन्न प्रकारों, प्रकारों के मिश्रण का उपयोग करना चाहते हैं, या अतिरिक्त मापदंडों को जोड़ना चाहते हैं, तब भी आपको लोड करना चाहिए। ओवरलोडिंग डिफ़ॉल्ट पैरामीटर के साथ तरीके बनाने का एक तरीका प्रदान करता है जहां परम = मान डिफ़ॉल्ट सिंटैक्स समर्थित नहीं है। मेरा जवाब देखें कि मेरा क्या मतलब है।
S.Robins

1
@blahman BTW और किसी अन्य विषय पर, जब आपके पास बहुत सारे पैरामीटर हैं और उनमें से कुछ वैकल्पिक हैं तो कभी-कभी केवल एक ऑब्जेक्ट या डेटा संरचना को भेजना बेहतर होता है जिसमें सभी डिफ़ॉल्ट मान होते हैं, इसलिए आप ऐसे ऑब्जेक्ट या डेटा की विशेषताओं को बदलते हैं संरचना। इस तरह आपको हर बार एक ही पैरामीटर जोड़ने के लिए एक ही विधि के 20 संस्करण बनाने की आवश्यकता नहीं है।
15
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.