अमूर्त वर्ग और इसके विपरीत के बजाय एक इंटरफ़ेस का उपयोग कब करें?


427

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

जब कोई एक इंटरफ़ेस का उपयोग करना चाहेगा और एक अमूर्त वर्ग का उपयोग कब करना चाहेगा ?


1
यह बहुत कुछ पूछा गया है: stackoverflow.com/questions/56867/interface-vs-base-class
mmcdole

1
नीचे दिए गए उत्तरों के अतिरिक्त में यह एक अच्छी छोटी सूची है कि आप कहाँ से इंटरफेस पसंद करना चाहते हैं और आप कहाँ नहीं हो सकते हैं: जब इंटरफेसेस का उपयोग करना है: msdn.microsoft.com/en-us/library/3b5b8ezk(v
एंथनी

सार का उपयोग करें जब आप सुनिश्चित करें कि कक्षा क्या करने जा रही है। यदि आप हैं तो इंटरफ़ेस का उपयोग करें
उउर गुम्मशान

मुझे यह देखने में रुचि है कि कितने डेवलपर, जो Microsoft पर काम नहीं करते हैं, अपने दिन के विकास में इंटरफेस को परिभाषित और उपयोग करते हैं।
user1451111

जवाबों:


431

मैंने उस बारे में एक लेख लिखा है:

सार वर्ग और इंटरफेस

सारांश:

जब हम अमूर्त वर्गों के बारे में बात करते हैं तो हम एक वस्तु प्रकार की विशेषताओं को परिभाषित कर रहे हैं; वस्तु क्या है, यह निर्दिष्ट करना

जब हम एक इंटरफ़ेस के बारे में बात करते हैं और क्षमताओं को परिभाषित करते हैं जो हम प्रदान करने का वादा करते हैं, तो हम इस बारे में एक अनुबंध स्थापित करने के बारे में बात कर रहे हैं कि ऑब्जेक्ट क्या कर सकता है।


114
यह इरी सहायक था Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk":। धन्यवाद
aexl

2
ऐसा लगता है कि आपका लिंक मर चुका है।
किम अहलस्त्रम मेयन माथियासेन

नीचे एलेक्स की व्याख्या, फिर से: केवल वर्णित कार्यों के वर्णन के बीच का अंतर, जिसे राज्य संग्रहीत भी वर्णित किया गया है, इस प्रश्न का बेहतर उत्तर लगता है, क्योंकि अंतर केवल दार्शनिक नहीं हैं।
डंकन मैलाशॉक

1
डंकन मैलाशॉक, वास्तव में नहीं। जोर्ज का जवाब बेहतर है। एलेक्स का जवाब यांत्रिकी पर केंद्रित है, जबकि जॉर्ज के शब्दार्थ पर।
नज़र मर्ज़ा

8
मुझे आपके निर्दिष्ट उत्तर से पहले बयान पसंद है:Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
S1r-Lanzelot

433

एक अमूर्त वर्ग साझा राज्य या कार्यक्षमता हो सकता है। एक इंटरफ़ेस केवल राज्य या कार्यक्षमता प्रदान करने का एक वादा है। एक अच्छा अमूर्त वर्ग कोड की मात्रा को कम कर देगा जिसे फिर से लिखना होगा क्योंकि यह कार्यक्षमता या राज्य साझा किया जा सकता है। इंटरफ़ेस को साझा करने के लिए कोई परिभाषित जानकारी नहीं है


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

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

1
मुझे लगता है कि जॉर्ज का सारांश दोनों के लिए अस्तित्व के पीछे प्राथमिक व्याख्या करता है जबकि एलेक्स का जवाब परिणामों में अंतर है। काश मैं सही उत्तर के रूप में दोनों को चिह्नित कर सकता, लेकिन मैं अभी भी जॉर्ज के उत्तर को पसंद करता हूं।
चिरंतन

और यहाँ है उदाहरण के कोड के साथ।
शाजुट

मेरे लिए, यह "एक अच्छा अमूर्त वर्ग कोड की मात्रा को कम कर देगा जिसे फिर से लिखना होगा क्योंकि यह कार्यक्षमता या राज्य साझा किया जा सकता है।" कथन उत्तर का मूल है।
तिवारी

82

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

ज्यादातर बार मैं अमूर्त कक्षाओं को (मिस) उपयोग करते हुए देखता हूं, ऐसा इसलिए है क्योंकि अमूर्त वर्ग के लेखक "टेम्पलेट विधि" पैटर्न का उपयोग कर रहे हैं।

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

(अत्यधिक सरलीकृत) उदाहरण:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

तो यहाँ, इस वर्ग के लेखक ने एक सामान्य एल्गोरिथ्म लिखा है और लोगों को इसे "स्वयं" हुक प्रदान करके "इसका उपयोग" करने का इरादा है - इस मामले में, एक "तुलना" विधि।

तो इच्छित उपयोग कुछ इस तरह है:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

इसके साथ समस्या यह है कि आपने दो अवधारणाओं को एक साथ जोड़ दिया है:

  1. दो वस्तुओं की तुलना करने का एक तरीका (किस आइटम को पहले जाना चाहिए)
  2. आइटम सॉर्ट करने का एक तरीका (यानी क्विकॉर्ट वर्स मर्ज सॉर्ट आदि)

उपरोक्त कोड में, सैद्धांतिक रूप से, "तुलना" विधि के लेखक सुपरक्लास "सॉर्ट" पद्धति में फिर से प्रवेश कर सकते हैं ... भले ही व्यवहार में वे कभी ऐसा नहीं करना चाहेंगे या करने की आवश्यकता नहीं होगी।

इस अनावश्यक युग्मन के लिए आप जो मूल्य अदा करते हैं, वह यह है कि सुपरक्लास को बदलना कठिन है, और अधिकांश OO भाषाओं में, इसे रनटाइम में बदलना असंभव है।

वैकल्पिक विधि इसके बजाय "रणनीति" डिजाइन पैटर्न का उपयोग करना है:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

तो अब ध्यान दें: हमारे पास सभी इंटरफेस हैं, और उन इंटरफेस के ठोस कार्यान्वयन हैं। व्यवहार में, आपको उच्च स्तरीय OO डिज़ाइन करने के लिए वास्तव में किसी और चीज़ की आवश्यकता नहीं है।

"QuickSort" वर्ग और "NameComparator" का उपयोग करके "नामों को छांटने" वाले तथ्य को "छिपाने" के लिए, हम अभी भी कहीं न कहीं एक कारखाना विधि लिख सकते हैं:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

किसी भी समय आपके पास एक अमूर्त वर्ग है जो आप ऐसा कर सकते हैं ... यहां तक ​​कि जब आधार और व्युत्पन्न वर्ग के बीच एक प्राकृतिक फिर से प्रवेश संबंध होता है, तो यह आमतौर पर उन्हें स्पष्ट करने के लिए भुगतान करता है।

एक अंतिम विचार: ऊपर हमने जो भी किया है वह "क्विकसॉर्ट" फ़ंक्शन और "नेम कॉमपर्सन" फ़ंक्शन का उपयोग करके "NameSorting" फ़ंक्शन की रचना है ... एक कार्यात्मक प्रोग्रामिंग भाषा में, प्रोग्रामिंग की यह शैली और भी स्वाभाविक हो जाती है, कम कोड के साथ।


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

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

ठीक है, मैंने इसे एक बार एक विशेषज्ञ प्रणाली के लिए उपयोग किया था, जहां प्रक्रिया कुछ इस तरह थी, 1 प्राप्त करें। FillTheParameters, 2. उनके बीच वेक्टर उत्पाद बनाएं, 3. प्रत्येक जोड़ी गणना परिणाम के लिए, 4. परिणाम में शामिल हों, जहां चरण 1 और 3 शामिल हों जहां प्रतिनिधि और 2 और 4 बेस क्लास में लागू किए गए।
जॉर्ज कोर्डोबा

10
मुझे अमूर्त वर्गों का लगभग कोई भी उपयोग कठिन लगता है। विरासत संबंधों के बजाय एक दूसरे के साथ संवाद करने वाले बक्से के संदर्भ में सोचना आसान है (मेरे लिए) ... लेकिन मैं यह भी मानता हूं कि वर्तमान ओओ भाषाएं बहुत अधिक बॉयलरप्लेट करती हैं ... कार्यात्मक ओओ पर जाने का तरीका होगा
पॉल हॉलिंगवर्थ

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

41

यदि आप जावा को ओओपी भाषा के रूप में देख रहे हैं,

" इंटरफ़ेस पद्धति कार्यान्वयन प्रदान नहीं करता है " जावा 8 लॉन्च के साथ अब मान्य नहीं है। अब जावा डिफ़ॉल्ट तरीकों के लिए इंटरफ़ेस में कार्यान्वयन प्रदान करता है।

सरल शब्दों में, मैं उपयोग करना चाहूंगा

इंटरफ़ेस: कई असंबंधित वस्तुओं द्वारा एक अनुबंध को लागू करने के लिए। यह " एचएएस ए " क्षमताप्रदान करताहै।

अमूर्त वर्ग: कई संबंधित वस्तुओं के बीच एक ही या अलग व्यवहार को लागू करने के लिए। यह " आईएस ए " संबंधस्थापित करता है

Oracle वेबसाइट , वर्ग interfaceऔर abstractवर्ग के बीच महत्वपूर्ण अंतर प्रदान करती है ।

अमूर्त कक्षाओं का उपयोग करने पर विचार करें यदि:

  1. आप कई निकट संबंधित वर्गों के बीच कोड साझा करना चाहते हैं।
  2. आप उम्मीद करते हैं कि आपके अमूर्त वर्ग का विस्तार करने वाले वर्गों के पास कई सामान्य तरीके या क्षेत्र हैं, या उन्हें सार्वजनिक (जैसे संरक्षित और निजी) के अलावा अन्य पहुँच संशोधक की आवश्यकता होती है।
  3. आप गैर-स्थिर या गैर-अंतिम फ़ील्ड घोषित करना चाहते हैं।

यदि इंटरफेस का उपयोग करने पर विचार करें :

  1. आप उम्मीद करते हैं कि असंबंधित वर्ग आपके इंटरफ़ेस को लागू करेंगे। उदाहरण के लिए, कई असंबंधित ऑब्जेक्ट Serializableइंटरफ़ेस को लागू कर सकते हैं ।
  2. आप किसी विशेष डेटा प्रकार के व्यवहार को निर्दिष्ट करना चाहते हैं, लेकिन इसके व्यवहार को लागू करने के बारे में चिंतित नहीं हैं।
  3. आप कई प्रकार की विरासत का लाभ उठाना चाहते हैं।

उदाहरण:

सार वर्ग ( एक रिश्ता है)

पाठक एक अमूर्त वर्ग है।

बफ़रड्रेडर एक हैReader

FileReader एक हैReader

FileReaderऔर BufferedReaderआम उद्देश्य के लिए उपयोग किया जाता है: डेटा पढ़ना, और वे Readerकक्षा के माध्यम से संबंधित हैं ।

इंटरफ़ेस ( एचए ए क्षमता)

Serializable एक इंटरफ़ेस है।

मान लें कि आपके आवेदन में दो कक्षाएं हैं, जो Serializableइंटरफ़ेस लागू कर रहे हैं

Employee implements Serializable

Game implements Serializable

यहां आप Serializableइंटरफ़ेस के माध्यम से कोई संबंध स्थापित नहीं कर सकते हैं Employeeऔर Game, जो अलग-अलग उद्देश्य के लिए हैं। दोनों राज्य को सीरियलाइज़ करने में सक्षम हैं और तुलना वहीं समाप्त होती है।

इन पदों पर एक नजर:

मुझे इंटरफ़ेस और अमूर्त वर्ग के बीच अंतर कैसे समझाया जाना चाहिए?


40

ठीक है, अपने आप को यह "पक्का" कर रहा है - यहाँ यह आम आदमी की शर्तों में है (अगर मुझे गलत लगता है तो मुझे सुधारने के लिए स्वतंत्र महसूस करें) - मुझे पता है कि यह विषय एक दिन का है, लेकिन हो सकता है कि कोई और इसे एक दिन ठोकर खाए ...

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

दूसरी ओर एक इंटरफ़ेस केवल आपको यह घोषित करने की अनुमति देता है कि आप सभी वर्गों में मौजूद किसी नाम के साथ गुण और / या विधियाँ चाहते हैं जो इसे लागू करते हैं - लेकिन यह निर्दिष्ट नहीं करता है कि आपको इसे कैसे लागू करना चाहिए। इसके अलावा, एक वर्ग MANY इंटरफेस को लागू कर सकता है, लेकिन केवल एक सार वर्ग का विस्तार कर सकता है। एक इंटरफ़ेस एक उच्च स्तर के वास्तुशिल्प उपकरण से अधिक है (जो डिज़ाइन पैटर्न को समझने के लिए शुरू होने पर स्पष्ट हो जाता है) - एक सार दोनों शिविरों में एक पैर होता है और कुछ गंदे काम भी कर सकता है।

एक का उपयोग दूसरे पर क्यों करें? पूर्व वंशजों की अधिक ठोस परिभाषा के लिए अनुमति देता है - उत्तरार्द्ध अधिक बहुरूपता की अनुमति देता है । यह अंतिम बिंदु अंतिम उपयोगकर्ता / कोडर के लिए महत्वपूर्ण है, जो अपनी आवश्यकताओं के अनुरूप संयोजन I / आकार में AP I (nterface) को लागू करने के लिए इस जानकारी का उपयोग कर सकते हैं।

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


इस पर निर्माण करने के लिए: एक वस्तु जो एक इंटरफ़ेस को लागू करती है वह TYPE है। यह महत्वपूर्ण है। इसलिए, आप इंटरफ़ेस के विभिन्न रूपों को एक वर्ग में पास कर सकते हैं, लेकिन उनके (और उनके तरीकों) को संदर्भ के प्रकार के नाम के साथ देखें। इस प्रकार, आप एक स्विच या यदि / और लूप की आवश्यकता को समाप्त करते हैं। इस ट्यूटोरियल को इस विषय पर आज़माएं - यह रणनीति पैटर्न के माध्यम से एक इंटरफ़ेस के उपयोग को दर्शाता है। phpfreaks.com/tutorial/design-patterns---strategy-and-bridge/…
sunwukung

मैं आपके लाइटबल्ब पल के बारे में पूरी तरह सहमत हूं: "एपीआई (nterface) विभिन्न प्रकार के संयोजन / आकार में उनकी आवश्यकताओं के अनुरूप है"! बनाने के लिए बहुत अच्छा बिंदु।
ट्रेवर बॉयड स्मिथ

39

मेरे दो सेंट:

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

दूसरी ओर, एक अमूर्त वर्ग में कोड हो सकता है, और सार के रूप में चिह्नित कुछ विधियाँ हो सकती हैं जिन्हें एक अनुगामी वर्ग को लागू करना चाहिए।

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

उदाहरण (एक बहुत ही मौलिक एक!): एक आधार वर्ग कहा जाता है ग्राहक जो की तरह अमूर्त तरीकों है पर विचार करें CalculatePayment(), CalculateRewardPoints()और जैसे कुछ गैर सार तरीकों GetName(), SavePaymentDetails()

की तरह विशेष कक्षाओं RegularCustomer और GoldCustomerसे प्राप्त कर लेंगे Customerआधार वर्ग और अपने स्वयं के लागू CalculatePayment()और CalculateRewardPoints()विधि तर्क है, लेकिन फिर से उपयोग करें GetName()और SavePaymentDetails()तरीकों।

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

सभी सार सदस्यों के साथ एक सार वर्ग एक इंटरफ़ेस के समान होगा।


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

इंटरफेस में "डिफ़ॉल्ट" तरीके हो सकते हैं ताकि इंटरफेस में निहित कोई भी तरीका गलत विचार न हो। "पैरेंट-टू-चाइल्ड" IS-A संबंध यहाँ की कुंजी है। इसके अलावा, "साझा गुण" बनाम "साझा गुण"। उदाहरण के लिए कुत्ता iS-A पशु। लेकिन एक कुत्ता "वॉक" भी कर सकता है
ha9u63ar

30

अगर आपके मन में अवधारणा स्पष्ट है तो क्या करना है, यह बहुत ही सरल बात है।

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

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

मुझे उम्मीद है कि मैं स्पष्ट हूं।


11

1.अगर आप कुछ ऐसा बना रहे हैं जो असंबद्ध वर्गों को सामान्य कार्यक्षमता प्रदान करता है, तो इंटरफ़ेस का उपयोग करें।

2.अगर आप उन वस्तुओं के लिए कुछ बना रहे हैं जो पदानुक्रम में निकट से संबंधित हैं, तो एक अमूर्त वर्ग का उपयोग करें।


10

मैंने एक लेख लिखा था कि अमूर्त वर्ग का उपयोग कब करना है और इंटरफ़ेस का उपयोग कब करना है। "एक IS-A ... और एक CAN-DO ..." के अलावा उनके बीच बहुत अंतर है। मेरे लिए, वे डिब्बाबंद जवाब हैं। मैं उनमें से किसी एक का उपयोग करने के कुछ कारणों का उल्लेख करता हूं। आशा है ये मदद करेगा।

http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/


7

मुझे लगता है कि इसे लगाने का सबसे सरल तरीका निम्नलिखित है:

साझा गुण => सार वर्ग।
साझा कार्यक्षमता => इंटरफ़ेस।

और इसे कम करने के लिए पूरी तरह से ...

सार वर्ग उदाहरण:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

चूंकि जानवरों के पास एक साझा संपत्ति है - इस मामले में पैरों की संख्या - यह एक सार वर्ग बनाने के लिए समझ में आता है जिसमें इस साझा संपत्ति होती है। इससे हम उस संपत्ति पर काम करने वाले सामान्य कोड को भी लिख सकते हैं। उदाहरण के लिए:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

इंटरफ़ेस उदाहरण:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

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

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

क्या आप बता सकते हैं कि आउटपुट क्या होगा?

अंत में, आप दोनों को जोड़ सकते हैं।

संयुक्त उदाहरण:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

यहाँ, हम सभी BaseAnimalको एक ध्वनि बनाने की आवश्यकता है , लेकिन हम इसके कार्यान्वयन को अभी तक नहीं जानते हैं। ऐसे मामले में, हम इंटरफ़ेस कार्यान्वयन को सार कर सकते हैं और इसके उपवर्गों को इसके कार्यान्वयन को सौंप सकते हैं।

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


7

इंटरफ़ेस पर एक अमूर्त वर्ग को कब पसंद करें?

  1. यदि किसी कार्यक्रम / परियोजना के पूरे जीवनकाल में एक आधार वर्ग को अद्यतन करने की योजना है, तो यह अनुमति देना सबसे अच्छा है कि आधार वर्ग एक सार वर्ग हो
  2. यदि कोई उन वस्तुओं के लिए एक रीढ़ बनाने की कोशिश कर रहा है जो एक पदानुक्रम में निकटता से संबंधित हैं, तो एक अभिजात वर्ग का उपयोग करना बहुत फायदेमंद है

अमूर्त वर्ग पर एक इंटरफ़ेस कब पसंद करना है?

  1. यदि कोई बड़े पैमाने पर पदानुक्रमित प्रकार के ढांचे के साथ काम नहीं कर रहा है, तो इंटरफेस एक बढ़िया विकल्प होगा
  2. क्योंकि मल्टीपल इनहेरिटेंस अमूर्त वर्गों (हीरे की समस्या) के साथ समर्थित नहीं है, इंटरफेस दिन बचा सकते हैं

क्या आपको लगता है कि लगभग एक दशक पुराने प्रश्न को 22 वें उत्तर की आवश्यकता थी?
जोंशरशेप

3
उसी प्रकार की सोच जिसने मुझे प्रश्न के सरल उत्तर की खोज की।
सत्य

1
FWIW, मैं वास्तव में इस जवाब से प्यार करता हूँ।
ब्रेंट रिटेनहाउस

6

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

आपके घटकों के लिए बहुरूपता प्रदान करने के लिए एक इंटरफ़ेस या एक सार वर्ग का उपयोग करने के लिए यह तय करने में आपकी सहायता करने के लिए यहां कुछ सिफारिशें दी गई हैं।

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

से कॉपी किया गया:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx


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

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

@supercat तुम्हारा कुछ समस्याओं में से कुछ का एक अच्छा विवरण है, जो कई विरासत का उपयोग करने के परिणामस्वरूप होता है। फिर भी, यूएमएल में ऐसा कुछ भी नहीं है जो एक आरेख में कई वर्ग उत्तराधिकार को रोकता है। मैं ऊपर का जवाब था "कक्षाएं केवल एक आधार वर्ग से विरासत में मिल सकती हैं ..." जो कि ऐसा नहीं है।
बॉब रोड्स

@ थोब्रेड: प्रश्न जावा को टैग किया गया था। जावा में संकेतित विशेषताएं शामिल हैं, और इस प्रकार कई वंशानुक्रम के रूपों तक सीमित है जो "घातक हीरे" का उत्पादन नहीं कर सकता है (हालांकि वास्तव में जिस तरह से उन्होंने डिफ़ॉल्ट इंटरफ़ेस कार्यान्वयन को लागू किया है वह घातक हीरे को संभव बनाता है)।
19

@supercat ओह, ठीक है। मैं आमतौर पर जावा टैग को नहीं देखता हूं, इसलिए उस समय मैंने लिखा था कि मुझे कम से कम लगता था कि मैं एक यूएमएल उत्तर पर टिप्पणी कर रहा हूं। किसी भी मामले में, मैं आपकी टिप्पणी से सहमत हूं।
बॉब रोड्स

3

यदि इनमें से कोई भी कथन आपकी स्थिति पर लागू होता है, तो अमूर्त कक्षाओं का उपयोग करने पर विचार करें :

  1. आप कई निकट संबंधित वर्गों के बीच कोड साझा करना चाहते हैं।
  2. आप उम्मीद करते हैं कि आपके अमूर्त वर्ग का विस्तार करने वाले वर्गों के पास कई सामान्य तरीके या क्षेत्र हैं या उन्हें सार्वजनिक (जैसे संरक्षित और निजी) के अलावा अन्य पहुँच संशोधक की आवश्यकता है।
  3. आप गैर-स्थिर या गैर-अंतिम फ़ील्ड घोषित करना चाहते हैं। यह आपको उन तरीकों को परिभाषित करने में सक्षम बनाता है जो उस वस्तु की स्थिति तक पहुंच और संशोधित कर सकते हैं जो वे हैं।

यदि इन कथनों में से कोई भी आपकी स्थिति पर लागू होता है, तो इंटरफेस का उपयोग करने पर विचार करें :

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

स्रोत


2

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


2

मेरे लिए, मैं कई मामलों में इंटरफेस के साथ जाऊंगा। लेकिन मैं कुछ मामलों में अमूर्त कक्षाएं पसंद करता हूं।

OO सामान्य में कक्षाएं कार्यान्वयन को संदर्भित करती हैं। मैं अमूर्त कक्षाओं का उपयोग करता हूं, जब मैं कुछ कार्यान्वयन विवरणों को मजबूर करना चाहता हूं, तो मैं इंटरफ़ेस के साथ जाता हूं।

बेशक, अमूर्त वर्ग न केवल कार्यान्वयन के लिए बल्कि कई संबंधित वर्गों के बीच कुछ विशिष्ट विवरणों को साझा करने में उपयोगी हैं।


1

यदि आप कुछ बुनियादी कार्यान्वयन प्रदान करना चाहते हैं तो एक सार वर्ग का उपयोग करें।


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

1
क्योंकि कुछ भाषाओं में इंटरफेस नहीं है - C ++।
jmucchiello

1

जावा में आपको कार्यक्षमता प्रदान करने के लिए एक (सार) वर्ग से विरासत में मिल सकता है और आप कार्यक्षमता सुनिश्चित करने के लिए कई इंटरफेस लागू कर सकते हैं


lil 'संकेत: यदि आप एक सार वर्ग और एक इंटरफ़ेस से विरासत में प्राप्त करना चाहते हैं, तो सुनिश्चित करें, कि सार वर्ग इंटरफ़ेस को लागू करता है
एंड्रियास नीडरमेयर

1

विशुद्ध रूप से वंशानुक्रम के आधार पर, आप एक ऐसे सार का उपयोग करेंगे जहां आप स्पष्ट रूप से वंशज, अमूर्त रिश्तों (अर्थात पशु-> बिल्ली) को परिभाषित कर रहे हैं और / या आभासी या गैर-सार्वजनिक संपत्तियों के उत्तराधिकार की आवश्यकता है, विशेष रूप से साझा स्थिति (जो इंटरफ़ेक्ट का समर्थन नहीं कर सकते हैं) )।

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


1

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


0

यह एक बहुत मुश्किल कॉल करने के लिए हो सकता है ...

एक पॉइंटर जो मैं दे सकता हूं: एक ऑब्जेक्ट कई इंटरफेस को लागू कर सकता है, जबकि एक ऑब्जेक्ट केवल एक बेस क्लास (आधुनिक ओओ भाषा में सी # की तरह प्राप्त कर सकता है, मुझे पता है कि सी ++ के पास कई विरासत हैं - लेकिन क्या यह नहीं है?)


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

वास्तव में मैं नहीं था, कई विरासत वास्तव में हमारे बीच एक निश्चित बहस का मुद्दा है, मुझे लगता है कि पूरी तरह से नीचा दिखाने का कोई कारण नहीं है। वास्तव में मैंने आपके उत्तर को गलत ठहराया।
मार्टिअन लार्मन

एकमात्र बिंदु जो मैंने बनाने की कोशिश की, वह यह है कि सिंगल इनहेरिटेंस वाली भाषाओं में मिक्सिन के तरीके भी संभव हैं (C #, PHP, जावास्क्रिप्ट) लेकिन गर्त हैकी व्यवहार या टैरिफ सिंटैक्स। मुझे मिक्सिन से प्यार है, जब वे काम करते हैं, लेकिन मैं अभी भी कई विरासत में या नहीं पर घरघराहट पर अनिर्णायक हूं।
मार्टिज़न लर्मन

यह उत्तर एक डिज़ाइन अंतर की तुलना में एक वाक्यात्मक अंतर है। मुझे लगता है कि वह एक डिजाइन अंतर के लिए पूछ रहा है
प्रमोद सेटलुर

0

एक अमूर्त वर्ग में कार्यान्वयन हो सकता है।

एक इंटरफ़ेस में कार्यान्वयन नहीं है, यह बस एक तरह के अनुबंध को परिभाषित करता है।

कुछ भाषा-निर्भर अंतर भी हो सकते हैं: उदाहरण के लिए C # में एकाधिक वंशानुक्रम नहीं है, लेकिन एक वर्ग में कई इंटरफेस लागू किए जा सकते हैं।


जब आप कहते हैं, "एक प्रकार का अनुबंध", तो क्या आपका मतलब वेब सेवाओं की तरह है?
चिरंतन

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

-1

मूल अंगूठे नियम है: "संज्ञा" के लिए सार वर्ग का उपयोग करें और "क्रिया" इंटरफ़ेस का उपयोग करें

जैसे: carएक अमूर्त वर्ग है और drive, हम इसे एक इंटरफ़ेस बना सकते हैं।


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