2013-01-01 9 views
19

मान लीजिए मैं निम्नलिखित स्थिति है:क्या इंटरफ़ेस की गारंटी देने का कोई तरीका जावा में कक्षा को बढ़ाता है?

public abstract class Vehicle { 
    public void turnOn() { ... } 
} 

public interface Flier { 
    public void fly(); 
} 

वहाँ एक रास्ता है कि मैं गारंटी ले सकते हैं कि किसी भी वर्ग कि Flier लागू करता भी Vehicle का विस्तार करना चाहिए है? मैं Flier एक अमूर्त वर्ग नहीं बनाना चाहता क्योंकि मैं कुछ अन्य इंटरफेस को इसी तरह से मिश्रण करने में सक्षम होना चाहता हूं।

उदाहरण के लिए:

// I also want to guarantee any class that implements Car must also implement Vehicle 
public interface Car { 
    public void honk(); 
} 

// I want the compiler to either give me an error saying 
// MySpecialMachine must extend Vehicle, or implicitly make 
// it a subclass of Vehicle. Either way, I want it to be 
// impossible to implement Car or Flier without also being 
// a subclass of Vehicle. 
public class MySpecialMachine implements Car, Flier { 
    public void honk() { ... } 
    public void fly() { ... } 
} 
+0

इंटरफेस इंटरफेस का विस्तार करते हैं। (सार) कक्षाएं (आंशिक रूप से) इंटरफेस को लागू करती हैं और अन्य कक्षाओं का विस्तार करती हैं। – asgs

+0

मेरे सुझाव का प्रयास करें, आप वाहन से विस्तार किए बिना MySpecialMachine संकलित नहीं कर सकते! –

उत्तर

22

जावा इंटरफेस कक्षाएं विस्तार नहीं कर सकते, जो समझ में आता है के बाद से कक्षाएं कार्यान्वयन विवरण है कि एक इंटरफेस के भीतर निर्दिष्ट नहीं किया जा सकता शामिल ..

इस समस्या से निपटने के लिए उचित तरीका है इंटरफेस में Vehicle को मोड़कर पूरी तरह से कार्यान्वयन से अंतरफलक को अलग करने के लिए। Car e.t.c. प्रोग्रामर को संबंधित विधियों को लागू करने के लिए मजबूर करने के लिए Vehicle इंटरफ़ेस का विस्तार कर सकते हैं। यदि आप सभी Vehicle उदाहरणों के बीच कोड साझा करना चाहते हैं, तो आप उस इंटरफ़ेस को लागू करने के लिए आवश्यक किसी भी कक्षा के लिए अभिभावक के रूप में एक (संभावित रूप से सार) कक्षा का उपयोग कर सकते हैं।

+0

अगर वह correspondimg विधियों को लागू नहीं कर सकता है? अगर वाहन केवल संबंधित तरीकों को लागू कर सकता है? के बारे में सोचो। –

+0

@ पीटररडर: मुझे समझ में नहीं आता कि आप क्या ले रहे हैं। उन्होंने पहले ही * वाहन 'में विधियों को लागू किया है। उसे बस इतना करना होगा कि 'वाहन' को एक इंटरफेस में बदल दें और यदि आवश्यक हो तो किसी कार्यान्वयन विवरण को एक सार आधार वर्ग में ले जाएं ... – thkala

+0

वाहन पहले से ही एक सार आधार वर्ग है। –

8

आप इस तरह अपनी कक्षाओं और इंटरफेस को पुनर्व्यवस्थित कर सकते हैं:

public interface IVehicle { 
    public void turnOn(); 
} 

public abstract class Vehicle implements IVehicle { 
    public void turnOn() { ... } 
} 

public interface Flier extends IVehicle { 
    public void fly(); 
} 

इस तरह Flier के सभी कार्यान्वयन प्रोटोकॉल एक वाहन के, अर्थात् IVehicle को लागू करने की गारंटी है।

+1

एक छोटा नाइटपिक - यदि 'I *' सम्मेलन का उपयोग किया जाना है (जो, बीटीडब्ल्यू, मुझे कभी भी जावा-वाई नहीं लग रहा था) तो इसका उपयोग * सभी * इंटरफेस के लिए किया जाना चाहिए ... – thkala

+0

@thkala: हाँ, 'I *' सम्मेलन मुख्य रूप से एक .NET चीज है। मैंने इसका इस्तेमाल किया क्योंकि मुझे अलग-अलग लेकिन संबंधित नाम की आवश्यकता थी 'वाहन'। निरंतर नामकरण के लिए नामों की सफाई करना निश्चित रूप से मदद करेगा। – Codo

1

यह प्रश्न दिखाता है कि आपने interface और class के सार को नहीं समझा है। कंक्रीट जावा सिंटैक्स को अभी भूलना, आपको पहले समझने की जरूरत है कि: इंटरफ़ेस प्रोटोकॉल का एक सेट है, जो कार्यान्वयन-अज्ञेयवादी होना चाहिए। इंटरफ़ेस को कक्षा को विस्तारित करने का कोई मतलब नहीं है (जो कार्यान्वयन उन्मुख है)।

अपने ठोस सवाल पर वापस, आप गारंटी नहीं है कि एक Flier हमेशा Vehicle की तरह है चाहते हैं, तो सिर्फ बाद एक interface को बदल सकते हैं और पूर्व यह फैली हुई हैं (यह समझ पड़ता है अन्य प्रोटोकॉल से एक प्रोटोकॉल का विस्तार करने के)। उसके बाद, आप कोई भी वर्ग (सार या ठोस) बना सकते हैं जो Vehicle या Flier लागू करता है।

+0

यह मामला हो सकता है, लेकिन ओप बाहरी ढांचे का उपयोग कर रहा है जिसमें 'वाहन' एक वर्ग है (भले ही यह एक इंटरफ़ेस होना चाहिए)। –

2

यह एक अजीब आवश्यकता है, लेकिन आप जेनेरिक्स के साथ एक तरह से कुछ को पूरा कर सकते हैं: (। यानी HiddenOne)

<T extends MyInterface & MyAbstractClass> 
0
  1. गुंजाइश "डिफ़ॉल्ट" के साथ परिभाषित एक नया पैकेज
  2. एक नया इंटरफ़ेस बनाएँ एक विधि "कार्यान्वयन (छुपे हुए)"
  3. वाहन और फ़्लियर को नए पैकेज में ले जाएं।
  4. छुपाए गए
  5. वाहन में लागू करने के तरीके को कार्यान्वित करें।

अब: जब भी आप "उड़ाका" से लागू करना चाहते तो आपको वाहन तक फैली हुई है! (क्योंकि केवल वाहन कार्यान्वित कर सकता है)।

यह मुश्किल है लेकिन बहुत अच्छा काम करता है।

+0

संरक्षित आंतरिक-वर्गों का उपयोग करके एक और जटिल समाधान भी है। –

+0

क्या होगा यदि कोई उस नए पैकेज के भीतर 'सबमरीन' कक्षा बनाता है? फिर वे 'छुपे हुए' को सीधे 'वाहन' के बिना बिना लागू कर सकते थे ... – thkala

+0

आप सुरक्षा-नियमों के साथ अपने पैकेज की रक्षा कर सकते हैं। लेकिन ... ठीक है, संरक्षित-आंतरिक-वर्ग आसान हो सकता है। –

1

यदि आपके पास Vehicle कक्षाओं पर नियंत्रण है तो बस इंटरफ़ेस के रूप में Vehicle निकालें और फिर आधार कार्यान्वयन प्रदान करें।

यदि आपके पास Vehicle क्लास पर कोई नियंत्रण नहीं है, उदाहरण के लिए क्योंकि यह आपके द्वारा उपयोग किए जा रहे ढांचे का हिस्सा है या तृतीय पक्ष लाइब्रेरी है, तो जावा में ऐसा करना संभव नहीं है।

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

<T extends Vehicle & Car> 

लेकिन क्या तुम सच में यह सीधे कार के लिए लागू नहीं कर सकते हैं जब तक आप कुछ इस तरह करते हैं:

public interface Car<T extends Vehicle & Car>() { 
    T self(); 
} 

कौन सा बॉट अजीब है और वास्तव में वापस जाने के लिए स्वयं आत्म विधि लागू नहीं है, यह सिर्फ है एक मजबूत संकेत/सुझाव।

आप एक Car इस तरह लागू करना होगा:

public class CitroenC3 extends Vehicle implements Car<CitroenC3> { 
    @Override 
    public CitroenC3 self() { 
     return this; 
    } 
} 

एक एक Car<?> इस तरह उपयोग कर सकते हैं:

Car<?> car = obtainCarInSomeWay(); 
Vehicle v = car.self(); 
Car c = car.self(); 

वे दोनों मान्य सिंटैक्स होना चाहिए।

क्या संकलक यहाँ लागू है जो आपके द्वारा जो दोनों के रूप में Vehicle का विस्तार करने और Car को लागू करना चाहिए Car<WHICH> में निर्दिष्ट करेंगे। और self() जोड़कर आप प्रोग्रामर से कह रहे हैं कि T ऑब्जेक्ट ऑब्जेक्ट स्वयं ही माना जाता है, इस प्रकार वाइल्डकार्ड इंस्टेंस को क्लास से मिलान करने के लिए मजबूर करना पड़ता है यदि वह विनिर्देश के अनुरूप होना चाहता है।

जावा 8 में आप स्वयं विधि के लिए एक डिफ़ॉल्ट कार्यान्वयन भी परिभाषित कर सकते हैं।

मैं यह भी चाहता हूं कि इस तरह कुछ संभालने का एक बेहतर तरीका था।

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

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