क्या एक इंटरफेस को 'खाली' माना जाता है अगर यह अन्य इंटरफेस से विरासत में मिला है?


12

खाली इंटरफेस आमतौर पर बुरा व्यवहार माना जाता है, जहां तक ​​मैं बता सकता हूं - विशेषकर जहां विशेषताओं जैसी चीजें भाषा द्वारा समर्थित हैं।

हालांकि, क्या एक इंटरफ़ेस को 'खाली' माना जाता है अगर यह अन्य इंटरफेस से विरासत में मिला है?

interface I1 { ... }
interface I2 { ... } //unrelated to I1

interface I3
    : I1, I2
{
    // empty body
}

कोई भी चीज जो औजार I3लागू करने के लिए की आवश्यकता होगी I1और I2, और विभिन्न वर्गों कि इनहेरिट से वस्तुओं I3, तो दूसरे के स्थान पर इस्तेमाल किया जा सकता (नीचे देखें) तो यह सही कॉल करने के लिए है I3 खाली ? यदि ऐसा है तो यह वास्तुकला का एक बेहतर तरीका क्या होगा?

// with I3 interface
class A : I3 { ... }
class B : I3 { ... }

class Test {
    void foo() {
        I3 something = new A();
        something = new B();
        something.SomeI1Function();
        something.SomeI2Function();
    }
}

// without I3 interface
class A : I1, I2 { ... }
class B : I1, I2 { ... }

class Test {
    void foo() {
        I1 something = new A();
        something = new B();
        something.SomeI1Function();
        something.SomeI2Function(); // we can't do this without casting first
    }
}

1
पैरामीटर / फ़ील्ड आदि के प्रकार के रूप में कई इंटरफेस निर्दिष्ट करने में असमर्थ होना C # / .NET में एक डिज़ाइन दोष है।
कोडइंचौस

मुझे लगता है कि इस भाग की वास्तुकला का बेहतर तरीका एक अलग प्रश्न में जाना चाहिए। अभी स्वीकृत उत्तर का प्रश्न शीर्षक से कोई लेना-देना नहीं है।
कपोल २१'१५

@CodesInChaos नहीं, इसके नहीं क्योंकि पहले से ही ऐसा करने के दो तरीके हैं। एक इस सवाल में है, दूसरा तरीका विधि तर्क के लिए एक सामान्य प्रकार के पैरामीटर को निर्दिष्ट करना होगा और जहां दोनों इंटरफेस को निर्दिष्ट करने के लिए प्रतिबंध का उपयोग किया जाएगा।
एंडी

क्या यह समझ में आता है कि एक वर्ग जो I1 और I2 को लागू करता है, लेकिन I3 को नहीं , का उपयोग करने में सक्षम नहीं होना चाहिए foo? (यदि उत्तर "हां" है, तो आगे बढ़ें!)
user253751

@Andy Whilst मैं पूरी तरह से CodeInChaos के दावे से सहमत नहीं हूं कि यह एक दोष है जैसे कि, मुझे नहीं लगता कि विधि पर सामान्य प्रकार के पैरामीटर एक समाधान हैं - यह विधि के कार्यान्वयन में प्रयुक्त एक प्रकार को जानने की जिम्मेदारी को धक्का देता है विधि को बुला रहा है, जो गलत लगता है। शायद var : I1, I2 something = new A();स्थानीय चर के लिए कुछ वाक्यविन्यास अच्छा होगा (यदि हम कोनराड के उत्तर में उठाए गए अच्छे बिंदुओं को अनदेखा करते हैं)
काई

जवाबों:


27

कुछ भी जो I3 को लागू करता है, I1 और I2 को लागू करने की आवश्यकता होगी, और I3 को प्राप्त करने वाले विभिन्न वर्गों से वस्तुओं को तब परस्पर विनिमय (नीचे देखें) का उपयोग किया जा सकता है, इसलिए क्या I3 को खाली कहना सही है? यदि ऐसा है तो यह वास्तुकला का एक बेहतर तरीका क्या होगा?

"बंडलिंग" I1और I2में I3प्रदान करता है एक अच्छा (?) शॉर्टकट, या जहाँ भी आप चाहते हैं दोनों लागू किया जाना वाक्य विन्यास को चीनी के कुछ प्रकार।

इस दृष्टिकोण के साथ समस्या यह है कि आप अन्य डेवलपर्स को स्पष्ट रूप से लागू करने I1 और I2 अगल - बगल से रोक नहीं सकते हैं , लेकिन यह दोनों तरीकों से काम नहीं करता है - जबकि : I3इसके बराबर है : I1, I2, के : I1, I2बराबर नहीं है : I3। भले ही वे कार्यात्मक रूप से समान हों, एक वर्ग जो दोनों का समर्थन करता है I1और I2समर्थन के रूप में नहीं पाया जाएगा I3

इसका मतलब है कि आप एक ही चीज़ को पूरा करने के दो तरीके पेश कर रहे हैं - "मैनुअल" और "स्वीट" (अपने सिंटेक्स शुगर के साथ)। और यह कोड संगतता पर बुरा प्रभाव डाल सकता है। एक ही चीज़ को पूरा करने के लिए 2 अलग-अलग तरीके यहाँ, वहाँ, और दूसरी जगह 8 संभावित संयोजनों के परिणाम पहले से ही दे रहे हैं :)

void foo() {
    I1 something = new A();
    something = new B();
    something.SomeI1Function();
    something.SomeI2Function(); // we can't do this without casting first
}

ठीक है, तुम नहीं कर सकते। लेकिन शायद यह वास्तव में एक अच्छा संकेत है?

यदि I1और I2अलग-अलग ज़िम्मेदारियाँ हैं (अन्यथा उन्हें पहली बार में अलग करने की कोई आवश्यकता नहीं होगी), तो शायद एक ही बार में दो अलग-अलग ज़िम्मेदारियों को निभाने की foo()कोशिश करना गलत है something?

दूसरे शब्दों में, यह हो सकता है कि foo()स्वयं सिंगल रिस्पॉन्सिबिलिटी के सिद्धांत का उल्लंघन करता है, और यह तथ्य कि इसे खींचने के लिए कास्टिंग और रनटाइम प्रकार की जांच की आवश्यकता होती है, एक लाल झंडा है जो हमें इसके बारे में चिंतित करता है।

संपादित करें:

यदि आप यह सुनिश्चित करने पर जोर देते हैं कि fooकुछ ऐसा है जो लागू करता है I1और I2, आप उन्हें अलग मापदंडों के रूप में पारित कर सकते हैं:

void foo(I1 i1, I2 i2) 

और वे एक ही वस्तु हो सकते हैं:

foo(something, something);

fooयदि वे एक ही उदाहरण हैं या नहीं तो क्या परवाह है?

लेकिन अगर यह परवाह करता है (जैसे कि क्योंकि वे स्टेटलेस नहीं हैं), या आपको लगता है कि यह बदसूरत लग रहा है, तो कोई इसके बजाय जेनरिक का उपयोग कर सकता है:

void Foo<T>(T something) where T: I1, I2

अब सामान्य बाधाएं बाहरी दुनिया को किसी भी चीज़ के साथ प्रदूषित नहीं करते हुए वांछित प्रभाव का ख्याल रखती हैं। यह मुहावरेदार सी # है, संकलन-समय की जाँच के आधार पर, और यह समग्र रूप से अधिक सही लगता है।

मैं I3 : I2, I1कुछ प्रकार की भाषा में यूनियन प्रकारों का अनुकरण करने के प्रयास के रूप में देखता हूं जो इसे बॉक्स से बाहर का समर्थन नहीं करता है (C # या Java नहीं, जबकि कार्यात्मक भाषाओं में यूनियन प्रकार मौजूद हैं)।

एक ऐसे निर्माण का अनुकरण करने की कोशिश करना जो वास्तव में भाषा द्वारा समर्थित नहीं है, अक्सर अकड़ता है। इसी तरह, सी # में आप अगर आप का अनुकरण करना चाहते हैं विस्तार के तरीकों और इंटरफेस का उपयोग कर सकते mixins । मुमकिन? हाँ। अच्छा विचार? मुझे यकीन नहीं है।


4

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

मैं आपको याद दिलाता हूं कि आप एक अमूर्त वर्ग बना सकते हैं जो दोनों इंटरफेस से विरासत में मिला है, और आप I3 के स्थान पर उस सार वर्ग का उपयोग कर सकते हैं। मुझे लगता है कि यह कहना गलत होगा कि आपको ऐसा नहीं करना चाहिए, लेकिन आपको कम से कम इसका एक अच्छा कारण होना चाहिए।


है ना? आप निश्चित रूप से एक ही कक्षा में दो इंटरफेस लागू कर सकते हैं। आपको इंटरफ़ेस विरासत में नहीं मिलता है, आप उन्हें लागू करते हैं।
एंडी

@ और कहां मैंने कहा कि एक एकल वर्ग दो इंटरफेस को लागू नहीं कर सकता है? "कार्यान्वित", शब्दार्थ के स्थान पर "विरासत" शब्द के उपयोग की चिंता किस बात के लिए है। C ++ में, इनहेरिट बिल्कुल ठीक बाद से इंटरफेस के निकटतम बात काम करेगा कर रहे हैं सार कक्षाएं।
नील

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

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

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

2

खाली इंटरफेस आमतौर पर बुरा अभ्यास माना जाता है

मैं असहमत हूं। मार्कर इंटरफेस के बारे में पढ़ें ।

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


मुझे लगता है कि ओपी उनके बारे में जानता है, लेकिन वे वास्तव में थोड़ा विवादास्पद हैं। जबकि कुछ लेखक उन्हें सलाह देते हैं (उदाहरण के लिए "प्रभावी जावा" में जोश बलोच), कुछ का दावा है कि वे एक एंटीपैटर्न और विरासत हैं जब जावा का अभी तक कोई एनोटेशन नहीं था। (जावा में एनोटेशन लगभग .NET में विशेषताओं के बराबर हैं)। मेरी धारणा है कि वे .NET की तुलना में जावा दुनिया में बहुत अधिक लोकप्रिय हैं।
कोनराड मोरावस्की

1
मैं एक समय में एक बार उनका उपयोग करता हूं, लेकिन यह थोड़े हैकिश महसूस करता है - मेरे सिर के ऊपर से डाउनसाइड, यह है कि आप इस तथ्य की मदद नहीं कर सकते हैं कि वे विरासत में मिले हैं, इसलिए एक बार जब आप एक कक्षा को चिह्नित करते हैं, तो उसके सभी बच्चे मिल जाते हैं आप चाहते हैं या नहीं के रूप में चिह्नित। और वे instanceof
बहुरूपवाद के
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.