2010-12-11 11 views
7

इसलिए मैंने पहले इस सवाल से पूछा लेकिन मुझे उस कोड में गलती हुई जो ज्यादातर लोगों ने समस्या के बजाए उठाया।जावा: विधि को ओवरराइड करते समय पैरामीटर के सबक्लास/सबटाइप को प्रतिस्थापित करना?

वैसे भी, मैं कक्षा में एक इंटरफ़ेस विधि को ओवरराइड करने का प्रयास कर रहा हूं। हालांकि, मैं ओवरराइडिंग विधि में पैरामीटर के प्रकार को ओवरराइड विधि में परिभाषित पैरामीटर के प्रकार का उप-वर्ग होना चाहता हूं।

इंटरफेस है:

public interface Observer { 
public void update(ComponentUpdateEvent updateEvent) throws Exception; 
} 

जबकि वर्ग है कि इस विधि को ओवरराइड करता है:

public class ConsoleDrawer extends Drawer { 

//... 

@Override 
public void update(ConsoleUpdateEvent updateEvent) throws Exception { 
    if (this.componentType != updateEvent.getComponentType()) { 
    throw new Exception("ComponentType Mismatch."); 
    } 
    else { 
    messages = updateEvent.getComponentState(); 
    } 
} 

//... 

} 

ConsoleUpdateEvent ComponentUpdateEvent का एक उपवर्ग है।

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

+5

मुझे विश्वास नहीं है क्योंकि यह एक इंटरफेस के सिद्धांत के खिलाफ है (यानी कक्षाएं जो इंटरफ़ेस को कार्यान्वित करती हैं, इंटरफ़ेस द्वारा निर्दिष्ट सभी विधि हस्ताक्षरों से बिल्कुल मेल खाती हैं)। हालांकि, मैं इस सवाल को देखूंगा क्योंकि मुझे यह देखने में बहुत दिलचस्पी है कि कोई और मुझे गलत साबित करेगा या नहीं। – DGH

उत्तर

2

आप निम्न का प्रयास कर सकते हैं। @Deprecated एक चेतावनी उत्पन्न करता है अगर संकलक जानता है कि आप दूसरे की बजाय पहली विधि को कॉल करेंगे।

@Override @Deprecated 
public void update(ComponentUpdateEvent updateEvent) { 
    // throws a ClassCastException if its not the right type. 
    update((ConsoleUpdateEvent) updateEvent); 
} 

public void update(ConsoleUpdateEvent updateEvent) { 
    messages = updateEvent.getComponentState(); 
} 

Btw: तुम बस नहीं डालने चाहिए, सब कुछ पर अपवाद फेंकता है। यह निश्चित रूप से सबसे अच्छा अभ्यास नहीं है।

संपादित करें: मैंने इस समस्या का एक अलग समाधान लागू किया है जो ओएसजीआई के साथ अच्छी तरह से काम करता है लेकिन कहीं भी काम कर सकता है।

एक पर्यवेक्षक ब्रोकर के साथ खुद को पंजीकृत करता है और ऑब्जर्वर कॉलबैक जैसे एनोटेशन के साथ विधियों को ढूंढने की अपेक्षा करता है।

उदा।

public class ConsoleDrawer extends Drawer { 
@ObserverCallback 
public void onConsoleUpdateEvent(ConsoleUpdateEvent updateEvent) { 
    messages = updateEvent.getComponentState(); 
} 
} 

public class DeviceDrawer extends Drawer { 
@ObserverCallback 
public void onDeviceUpdateEvent(DeviceUpdateEvent updateEvent) { 
    // do something. 
} 
} 

पहले मामले में, दलाल @ObserverCallback जो एक तर्क लेता के साथ एक विधि पाता है। यह एकमात्र प्रकार है जो ब्रोकर इसे पास करेगा। दूसरी कक्षा एक अलग प्रकार की उम्मीद है। पर्यवेक्षकों के पास कई प्रकार/प्रकार हो सकते हैं जो उन्हें उस प्रकार के लिए उपयुक्त विभिन्न विधियों में विभिन्न संदेशों को संभालने की अनुमति देते हैं। आप यह भी जानते हैं कि आपको कभी भी डेटा प्रकार प्राप्त नहीं होगा जिसे आप उम्मीद नहीं करते हैं।

+0

मैं व्यक्तिगत रूप से (और कई अन्य लोगों से बात करता हूं) मूल उद्देश्य के अलावा किसी अन्य चीज़ के लिए बहिष्कृत टैग का उपयोग करके नापसंद करते हैं: चिह्नित विधियों को वैध माना जाता है लेकिन अब उन्हें बहिष्कृत किया जाता है। ऐसा कुछ और करने के लिए इसका उपयोग हैकर-आश लगता है। – DGH

+0

@ डीजीएच, विधि वैध (अभिभावक के लिए) प्रयोग की जाती थी लेकिन अब इस वर्ग के लिए मान्य नहीं है। ;) हालांकि मैं आपका मुद्दा लेता हूं। आदर्श रूप से एक टैग होगा जो एक कंपाइलर त्रुटि उत्पन्न करता है। अपडेट() विधि को डिजाइन करना भी बेहतर होगा ताकि सभी कार्यान्वयन अनुबंध को सम्मानित किया जा सके। –

+0

सुझाव के लिए धन्यवाद। पहले समाधान का उपयोग करना; मैंने दूसरी अद्यतन विधि को निजी शून्य addEventMessages (ConsoleUpdateEvent) {// ...} में बदल दिया और ऐसा लगता है कि यह उचित रूप से अच्छी तरह से काम करता है। – carnun

7

आप नहीं कर सकते। यह एफिल नहीं है। समस्या यह है कि आप एक असंगत प्रकार के साथ कार्यान्वयन विधि को कॉल करने के लिए इंटरफ़ेस का उपयोग कर सकते हैं। तो covariant पैरामीटर की अनुमति नहीं है। Contravariant पैरामीटर या तो अनुमति नहीं है, लेकिन एक अधिभार प्रदान करना आसान है। कॉन्वरेन्ट रिटर्न प्रकार की अनुमति है (1.5 के बाद से)।

आप इंटरफ़ेस parameterise सकता है:

public interface Observer<T extends ComponentEvent> { 
    void update(T event) throws Exception; 
} 

वैकल्पिक रूप से, और अधिक सार्थक इंटरफ़ेस का उपयोग:

public interface ConsoleObserver { 
    void update(ConsoleEvent event) throws Exception; 
} 
+1

यहां विस्तृत उत्तर मिला http://stackoverflow.com/a/9421315/1276636 – Sufian

2

OOP सिद्धांतों से जा रहे हैं, एक उप-वर्ग ठीक उसी तरह के रूप में में प्रयोग करने योग्य होना चाहिए अभिभावक वर्ग। उदा।

Observer ob = new ConsoleDrawer(); 
ob.update(new ComponentUpdateEvent()); // This needs to work always. 

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

इसलिए, एकमात्र तार्किक समाधान माता-पिता वर्ग पैरामीटर को स्वीकार करना है, इसे टाइप-चेक करें और फिर इसे आवश्यक उप प्रकार पर डालें।

संबंधित मुद्दे