C # में विस्तार विधियों के साथ इंटरफेस के बजाय अमूर्त कक्षाओं का उपयोग कब करें?


70

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

इंटरफ़ेस + विस्तार विधि मॉडल का एक उल्लेखनीय उदाहरण LINQ है, जहां क्वेरी कार्यक्षमता किसी भी प्रकार के लिए प्रदान की जाती है IEnumerableजो विस्तार विधियों की भीड़ के माध्यम से लागू होती है ।


2
और हम इंटरफेस में भी 'गुण' का उपयोग कर सकते हैं।
गुलशन ३१'११

1
सामान्य OOD प्रश्न के बजाय C # विशिष्ट जैसा लगता है। (अधिकांश अन्य OO भाषाओं में विस्तार विधियाँ नहीं हैं और न ही गुण हैं।)
Péter Török


4
एक्सटेंशन विधियाँ उस समस्या को काफी हल नहीं करती हैं जो अमूर्त वर्ग हल करते हैं, इसलिए इसका कारण जावा या कुछ अन्य समान एकल-विरासत भाषा से अलग नहीं है।
जॉब

3
विस्तार विधियों द्वारा अमूर्त वर्ग विधि के कार्यान्वयन की आवश्यकता कम नहीं हुई है । एक्सटेंशन के तरीके निजी सदस्य क्षेत्रों तक नहीं पहुंच सकते हैं, न ही उन्हें आभासी घोषित किया जा सकता है और व्युत्पन्न वर्गों में ओवरराइड किया जा सकता है।
zooone9243

जवाबों:


63

जब आपको लागू करने के लिए कक्षा का एक हिस्सा चाहिए। सबसे अच्छा उदाहरण मैंने प्रयोग किया है टेम्पलेट पद्धति पैटर्न।

public abstract class SomethingDoer
{
    public void Do()
    {
        this.DoThis();
        this.DoThat();
    }

    protected abstract void DoThis();
    protected abstract void DoThat();
}

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

एक्सटेंशन्स के तरीके जरूरी नहीं हैं कि "समीकरण का एक हिस्सा" वर्ग का हिस्सा होना चाहिए। इसके अतिरिक्त, iirc, विस्तार विधियाँ (कुछ भी) दिखाई नहीं दे सकती हैं लेकिन कार्यक्षेत्र में सार्वजनिक हैं।

संपादित करें

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

व्यक्तिगत रूप से, मुझे वर्तमान में सामान्य व्यवहार में परिवर्तन का लाभ देखने में परेशानी हो रही है, लेकिन इसे करने में कोई कमी नहीं है।

यह ध्यान दिया जाना चाहिए कि उपयोगिता कक्षाओं के माध्यम से कई भाषाओं में इस तरह से कार्यक्रम करना संभव है। एक्सटेंशन्स सिस्टेमैटिक शुगर प्रदान करते हैं ताकि वे विधियां बना सकें जैसे वे कक्षा से संबंधित हैं।


मुझे इसे मारो ..
जियोर्गी

1
लेकिन यही बात इंटरफेसेस और एक्सटेंशन के तरीकों से भी की जा सकती है। वहां आपके द्वारा अमूर्त आधार वर्ग में जिन विधियों को परिभाषित किया Do()जा रहा है , उन्हें विस्तार विधि के रूप में परिभाषित किया जाएगा। और व्युत्पन्न वर्गों की परिभाषा के लिए छोड़े गए तरीके DoThis()मुख्य इंटरफ़ेस के सदस्य होंगे। और इंटरफेस के साथ, आप कई कार्यान्वयन / विरासत का समर्थन कर सकते हैं। और इसे देखें- odetocode.com/blogs/scott/archive/2009/10/05/…
गुलशन

@ गुलशन: क्योंकि एक चीज़ को एक से अधिक तरीकों से किया जा सकता है जो चुने हुए तरीके को अमान्य नहीं बनाता है। इंटरफेस का उपयोग करने में कोई फायदा नहीं है। सार वर्ग ही है इंटरफ़ेस। आपको कई कार्यान्वयन का समर्थन करने के लिए इंटरफेस की आवश्यकता नहीं है।
थॉमसएक्स

इसके अलावा, इंटरफ़ेस + विस्तार मॉडल के नुकसान भी हो सकते हैं। मिसाल के तौर पर Linq लाइब्रेरी को ही लें। यह बहुत अच्छा है, लेकिन अगर आपको इसे केवल एक बार उस कोड फ़ाइल में उपयोग करने की आवश्यकता है, तो पूरी लिन्क लाइब्रेरी आपकी कोड फ़ाइल में कभी-कभी IEnumerable पर IntelliSense में उपलब्ध होगी। यह आईडीई प्रदर्शन को काफी धीमा कर सकता है।
कीथ्स

-1 क्योंकि आपने किसी भी तरह से प्रदर्शन नहीं किया है, जिसमें अमूर्त वर्ग इंटरफेस की तुलना में टेम्पलेट विधि के लिए बेहतर फिट हैं
बेंजामिन हॉजसन

25

यह वह सब है जो आप मॉडल करना चाहते हैं:

सार वर्ग विरासत द्वारा काम करते हैं । सिर्फ विशेष आधार वर्ग होने के नाते, वे कुछ -एक- प्रतिसंबंधी मॉडल रखते हैं।

उदाहरण के लिए, एक कुत्ता है एक जानवर है, इस प्रकार हमारे पास

class Dog : Animal { ... }

यह वास्तव में करने के लिए कोई मतलब नहीं है के रूप में बनाने के लिए एक सामान्य सभी जानवर (? यह कैसा लगेगा), हम इस बनाने के Animalआधार वर्ग abstract- लेकिन यह अभी भी एक आधार वर्ग है। और Dogवर्ग एक होने के बिना कोई मतलब नहीं है Animal

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

उदाहरण के लिए ले लो IComparable- एक वस्तु जो एक दूसरे के साथ तुलना की जा रही है

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

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


आप बेस क्लास सार को कब चुनना चाहेंगे?
गुलशन

1
@ गुलशन: अगर ऐसा होता है - किसी कारण से - वास्तव में आधार वर्ग का एक उदाहरण बनाने के लिए समझ में नहीं आता है। आप चिहुआहुआ या एक सफेद शार्क "बना" सकते हैं, लेकिन आप आगे विशेषज्ञता के बिना एक जानवर नहीं बना सकते हैं - इस प्रकार आप Animalअमूर्त बना देंगे । यह आपको abstractव्युत्पन्न वर्गों द्वारा विशेष किए जाने वाले कार्यों को लिखने में सक्षम बनाता है । या अधिक प्रोग्रामिंग संदर्भ में - यह शायद एक बनाने के लिए कोई मतलब नहीं पड़ता है UserControl, लेकिन के रूप में एक Button है एक UserControlहै, तो हम वर्ग / baseclass रिश्ते की एक ही तरह की है।
डारियो

यदि आपके पास अमूर्त विधियां हैं, तो आपके पास अमूर्त वर्ग है। और सार तरीके आपके पास हैं जब उन्हें लागू करने के लिए कोई मूल्य नहीं है (जैसे जानवर के लिए "जाना")। और निश्चित रूप से कभी-कभी आप कुछ सामान्य वर्ग की वस्तुओं की अनुमति नहीं देना चाहते हैं, क्योंकि आप इसे अमूर्त बनाते हैं।
Dainius

ऐसा कोई नियम नहीं है जो कहता है कि अगर यह "बी ए ए" कहने के लिए व्याकरणिक और शब्दार्थ से सार्थक है तो ए को एक सार वर्ग होना चाहिए। आपको तब तक इंटरफेस पसंद करना चाहिए जब तक आप वास्तव में क्लास से बच नहीं सकते। शेयरिंग कोड इंटरफेस की रचना के माध्यम से किया जा सकता है, आदि यह अजीब विरासत पेड़ों के साथ अपने आप को एक कोने में पेंटिंग से बचना आसान बनाता है।
सारा

3

मुझे बस एहसास हुआ, कि मैंने वर्षों में अमूर्त वर्ग (कम से कम नहीं बनाया गया) का उपयोग नहीं किया है।

सार वर्ग इंटरफ़ेस और कार्यान्वयन के बीच एक अजीब तरह का जानवर है। अमूर्त वर्गों में कुछ ऐसा है जो मेरी मकड़ी-सूँघता है। मैं तर्क दूंगा, किसी को भी किसी भी तरह से इंटरफ़ेस के पीछे कार्यान्वयन को "बेनकाब" नहीं करना चाहिए (या कोई टाई-इन करना चाहिए)।

यहां तक ​​कि अगर इंटरफ़ेस को लागू करने वाले वर्गों के बीच सामान्य व्यवहार की आवश्यकता है, तो मैं एक सार वर्ग के बजाय एक स्वतंत्र सहायक वर्ग का उपयोग करूंगा।

मैं इंटरफेस के लिए जाना होगा।


2
-1: मुझे यकीन नहीं है कि आप कितने वर्ष के हैं, लेकिन आप डिज़ाइन पैटर्न, विशेषकर टेम्पलेट पद्धति पैटर्न सीखना चाह सकते हैं। डिज़ाइन पैटर्न आपको एक बेहतर प्रोग्रामर बना देगा और वे आपके अमूर्त वर्गों की अज्ञानता को समाप्त कर देंगे।
जिम जी।

झुनझुनी सनसनी के बारे में भी। कक्षाएं, सी # और जावा की पहली और सबसे महत्वपूर्ण विशेषता, एक प्रकार बनाने और तुरंत इसे एक कार्यान्वयन के लिए हमेशा के लिए पीछा करने की एक विशेषता है।
जेसी मिलिकन

2

IMHO, मुझे लगता है कि यहाँ अवधारणाओं का मिश्रण है।

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

दोनों प्रकार की विरासत महत्वपूर्ण और उपयोगी है, और हर एक के पास इसके पेशेवरों और विपक्ष हैं।

चलिए शुरुआत करते हैं।

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

C ++ में केवल एक प्रकार की विरासत थी, वर्गों द्वारा उपयोग की जाने वाली विरासत का प्रकार, जिसे कार्यान्वयन विरासत कहा जाता है।

GoF बुक की सिफारिश को लागू करने में सक्षम होने के लिए: "इंटरफ़ेस के लिए प्रोग्राम करने के लिए, और कार्यान्वयन के लिए नहीं", C ++ ने अमूर्त वर्गों और कई कार्यान्वयन विरासत का समर्थन किया जो C # में इंटरफेस करने में सक्षम होने के लिए सक्षम (और उपयोगी!) करने में सक्षम हैं। ।

C # एक महत्वपूर्ण चेतावनी के साथ "इंटरफ़ेस के लिए प्रोग्राम करने के लिए, और कार्यान्वयन के लिए नहीं" का समर्थन करने के लिए कम से कम दो अलग-अलग तरीकों की पेशकश करने के लिए एक नए प्रकार के प्रकार, इंटरफेस, और एक नई तरह की विरासत, इंटरफ़ेस विरासत का परिचय देता है। इंटरफ़ेस वंशानुक्रम (और कार्यान्वयन विरासत के साथ नहीं) के साथ कई विरासत का समर्थन करता है।

तो, C # में इंटरफेस के पीछे का वास्तु कारण है GoF की सिफारिश।

मुझे उम्मीद है कि यह मदद की हो सकती है।

तरह का संबंध है, गैस्टोन


1

एक अंतरापृष्ठ पर सामान्य तरीकों को लागू करने के लिए एक इंटरफ़ेस में विस्तार विधियों को लागू करना उपयोगी है जो केवल एक सामान्य इंटरफ़ेस साझा कर सकता है। ऐसी कक्षाएं पहले से मौजूद हो सकती हैं और अन्य माध्यमों से एक्सटेंशन के लिए बंद हो सकती हैं।

नए डिजाइनों के लिए मैं इंटरफेस पर विस्तार के तरीकों के उपयोग का पक्ष लूंगा। प्रकारों की पदानुक्रम के लिए, विस्तार विधियाँ संशोधन के लिए संपूर्ण पदानुक्रम खोलने के लिए बिना व्यवहार का विस्तार करने का साधन प्रदान करती हैं।

हालांकि, विस्तार विधियां निजी कार्यान्वयन तक पहुंचने में असमर्थ हैं, इसलिए एक पदानुक्रम के शीर्ष पर, अगर मुझे सार्वजनिक इंटरफ़ेस के पीछे निजी कार्यान्वयन को इनकैप्सुलेट करने की आवश्यकता है, तो एक सार वर्ग एकमात्र तरीका होगा।


नहीं, यह एकमात्र सुरक्षित तरीका नहीं है। एक और सुरक्षित तरीका है। वह विस्तार विधियाँ हैं। ग्राहकों को संक्रमित नहीं किया जाएगा। इसलिए मैंने इंटरफेस + विस्तार विधियों का उल्लेख किया है।
गुलशन

@ ए डी जेम्स मुझे लगता है कि "कम शक्तिशाली" = "अधिक लचीला" आप अधिक लचीले इंटरफ़ेस के बजाय अधिक शक्तिशाली अमूर्त वर्ग का चयन कब करेंगे?
गुलशन

@Ed जेम्स Asp.mvc एक्सटेंशन के तरीकों का इस्तेमाल शुरू से ही किया जाता था। तुम उसके बारे में क्या सोचते हो?
गुलशन

0

मुझे लगता है कि C # मल्टीपल इनहेरिटेंस का समर्थन नहीं किया गया है और इसीलिए C # में इंटरफ़ेस का कॉन्सेप्ट पेश किया गया है।

अमूर्त वर्गों के मामले में, एकाधिक वंशानुक्रम का समर्थन नहीं किया जाता है। इसलिए सार वर्ग या इंटरफेस का उपयोग करने के लिए तार पर फैसला करना आसान है।


सटीक होने के लिए, यह शुद्ध सार कक्षाएं हैं जिन्हें C # में "इंटरफेस" कहा जाता है।
जोहान बोले

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.