oop इंटरफेस बनाम बेस क्लास




interface language-agnostic (24)

Use Interfaces to enforce a contract ACROSS families of unrelated classes. For example, you might have common access methods for classes that represent collections, but contain radically different data ie one class might represent a result set from a query, while the other might represent the images in a gallery. Also, you can implement multiple interfaces, thus allowing you to blend (and signify) the capabilities of the class.

कक्षाएं एक आम रिश्ते को सहन करते समय विरासत का उपयोग करें और इसलिए एक समान संरचनात्मक और व्यवहारिक हस्ताक्षर है, यानी कार, मोटरबाइक, ट्रक और एसयूवी सभी प्रकार के सड़क वाहन हैं जिनमें कई पहियों, एक शीर्ष गति हो सकती है

मुझे इंटरफ़ेस का उपयोग कब करना चाहिए और मुझे बेस क्लास का उपयोग कब करना चाहिए?

यदि मैं वास्तव में विधियों के मूल कार्यान्वयन को परिभाषित नहीं करना चाहता हूं तो क्या यह हमेशा एक इंटरफ़ेस होना चाहिए?

अगर मेरे पास कुत्ता और बिल्ली वर्ग है। मैं पेटबेस के बजाय आईपेट क्यों लागू करना चाहूंगा? मैं आइशेड या आईबार्क (IMakesNoise?) के लिए इंटरफेस रखने में समझ सकता हूं, क्योंकि उन्हें पालतू जानवरों के आधार पर पालतू जानवरों पर रखा जा सकता है, लेकिन मुझे समझ में नहीं आता कि सामान्य पालतू जानवर के लिए कौन सा उपयोग करना है।


@Joel: Some languages (eg, C++) allow multiple-inheritance.


इंटरफेस और बेस क्लास संबंधों के दो अलग-अलग रूपों का प्रतिनिधित्व करते हैं।

विरासत (आधार वर्ग) एक "एक-एक" संबंध का प्रतिनिधित्व करते हैं। एक कुत्ता या बिल्ली "एक-एक" पालतू जानवर है। यह संबंध हमेशा कक्षा के (एकल) उद्देश्य ( "एकल जिम्मेदारी सिद्धांत" के संयोजन के साथ) का प्रतिनिधित्व करता है।

दूसरी तरफ इंटरफेस , कक्षा की अतिरिक्त विशेषताओं का प्रतिनिधित्व करते हैं। मैं इसे "है" रिश्ते कहूंगा, जैसे " Foo डिस्पोजेबल" है, इसलिए सी # में IDisposable इंटरफ़ेस।


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


खैर, जोश ब्लोच ने खुद को प्रभावी जावा 2 डी में कहा:

अमूर्त वर्गों पर इंटरफेस पसंद करते हैं

कुछ मुख्य बिंदु:

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

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

  • इंटरफेस nonhierarchical प्रकार ढांचे के निर्माण की अनुमति देते हैं । टाइप करें पदानुक्रम कुछ चीजों को व्यवस्थित करने के लिए बहुत अच्छे हैं, लेकिन अन्य चीजें एक कठोर पदानुक्रम में अच्छी तरह से नहीं आती हैं।

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

इसके अलावा, आप निर्यात करने वाले प्रत्येक नॉनट्रिविअल इंटरफ़ेस के साथ जाने के लिए एक अमूर्त कंकाल कार्यान्वयन कक्षा प्रदान करके इंटरफेस और अमूर्त कक्षाओं के गुणों को जोड़ सकते हैं।

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

पीएस .: किताब खरीदें। यह बहुत अधिक विस्तृत है।


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

ओओडी में सार्वजनिक विरासत का अधिक उपयोग किया जाता है और अधिकांश डेवलपर्स के मुकाबले बहुत अधिक व्यक्त करता है या जीने के इच्छुक हैं। Liskov Substitutablity सिद्धांत देखें

संक्षेप में, यदि ए "ए" ए है तो ए को बी से अधिक की आवश्यकता नहीं है और बी से कम नहीं है, प्रत्येक विधि के लिए यह खुलासा करता है।


I've found that a pattern of Interface > Abstract > Concrete works in the following use-case:

1.  You have a general interface (eg IPet)
2.  You have a implementation that is less general (eg Mammal)
3.  You have many concrete members (eg Cat, Dog, Ape)

The abstract class defines default shared attributes of the concrete classes, yet enforces the interface. उदाहरण के लिए:

public interface IPet{

    public boolean hasHair();

    public boolean walksUprights();

    public boolean hasNipples();
}

Now, since all mammals have hair and nipples (AFAIK, I'm not a zoologist), we can roll this into the abstract base class

public abstract class Mammal() implements IPet{

     @override
     public walksUpright(){
         throw new NotSupportedException("Walks Upright not implemented");
     }

     @override
     public hasNipples(){return true}

     @override
     public hasHair(){return true}

And then the concrete classes merely define that they walk upright.

public class Ape extends Mammal(){

    @override
    public walksUpright(return true)
}

public class Catextends Mammal(){

    @override
    public walksUpright(return false)
}

This design is nice when there are lots of concrete classes, and you don't want to maintain boilerplate just to program to an interface. If new methods were added to the interface, it would break all of the resulting classes, so you are still getting the advantages of the interface approach.

In this case, the abstract could just as well be concrete; however, the abstract designation helps to emphasize that this pattern is being employed.


Prefer interfaces over abstract classes

Rationale, the main points to consider [two already mentioned here] are :

  • Interfaces are more flexible, because a class can implement multiple interfaces. Since Java does not have multiple inheritance, using abstract classes prevents your users from using any other class hierarchy. In general, prefer interfaces when there are no default implementations or state. Java collections offer good examples of this (Map, Set, etc.).
  • Abstract classes have the advantage of allowing better forward compatibility. Once clients use an interface, you cannot change it; if they use an abstract class, you can still add behavior without breaking existing code. If compatibility is a concern, consider using abstract classes.
  • Even if you do have default implementations or internal state, consider offering an interface and an abstract implementation of it . This will assist clients, but still allow them greater freedom if desired [1].
    Of course, the subject has been discussed at length elsewhere [2,3].

[1] It adds more code, of course, but if brevity is your primary concern, you probably should have avoided Java in the first place!

[2] Joshua Bloch, Effective Java, items 16-18.

[3] http://www.codeproject.com/KB/ar ...


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

चारों की गिरोह ने अपनी पुस्तक में कहा "क्योंकि विरासत अपने माता-पिता के कार्यान्वयन के ब्योरे के लिए एक उप-वर्ग का खुलासा करती है, अक्सर यह कहा जाता है कि 'विरासत टूटना encapsulation"। मुझे विश्वास है कि यह सच है।


इस जावा वर्ल्ड आलेख में अच्छी तरह से समझाया गया

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

यह असामान्य नहीं है कि मेरे पास 1 या अधिक इंटरफेस लागू करने वाली कक्षा होगी।

सार वर्ग मैं कुछ और के लिए आधार के रूप में उपयोग करते हैं।

उपर्युक्त आलेख JavaWorld.com आलेख, लेखक टोनी सिंट्स, 04/20/01 से निम्नलिखित निकास है

इंटरफेस बनाम अमूर्त वर्ग

इंटरफेस और अमूर्त कक्षाओं का चयन करना एक या / प्रस्ताव नहीं है। यदि आपको अपना डिज़ाइन बदलने की ज़रूरत है, तो इसे एक इंटरफ़ेस बनाएं। हालांकि, आपके पास अमूर्त कक्षाएं हो सकती हैं जो कुछ डिफ़ॉल्ट व्यवहार प्रदान करती हैं। सार कक्षाएं आवेदन ढांचे के अंदर उत्कृष्ट उम्मीदवार हैं।

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

कई डेवलपर्स भूल जाते हैं कि एक वर्ग जो एक अमूर्त विधि को परिभाषित करता है, वह विधि भी कॉल कर सकता है। सार कक्षाएं नियोजित विरासत पदानुक्रम बनाने का एक शानदार तरीका है। वे कक्षा पदानुक्रमों में nonleaf कक्षाओं के लिए भी एक अच्छा विकल्प हैं।

कक्षा बनाम इंटरफ़ेस

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

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

रणनीति पैटर्न के साथ, आप किसी वस्तु के पीछे एल्गोरिदम को आसानी से समाहित कर सकते हैं। यदि आप ऐसा करते हैं, तो आप किसी भी समय नए मीडिया प्लग-इन प्रदान कर सकते हैं। आइए प्लग-इन क्लास MediaStrategy को कॉल करें। उस ऑब्जेक्ट में एक विधि होगी: प्लेस्ट्रीम (स्ट्रीम एस)। तो एक नया एल्गोरिदम जोड़ने के लिए, हम बस हमारे एल्गोरिदम वर्ग का विस्तार करते हैं। अब, जब कार्यक्रम नए मीडिया प्रकार से मुकाबला करता है, तो यह आसानी से स्ट्रीम के खेल को हमारी मीडिया रणनीति में प्रस्तुत करता है। बेशक, आपको कुछ एल्गोरिदम रणनीतियों को तुरंत ठीक करने के लिए कुछ नलसाजी की आवश्यकता होगी।

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


इंटरफेस

  • 2 मॉड्यूल के बीच अनुबंध परिभाषित करता है। कोई कार्यान्वयन नहीं हो सकता है।
  • अधिकतर भाषाएं आपको कई इंटरफेस लागू करने की अनुमति देती हैं
  • एक इंटरफ़ेस को संशोधित करना एक तोड़ना परिवर्तन है। सभी कार्यान्वयन को पुन: संकलित / संशोधित करने की आवश्यकता है।
  • सभी सदस्य सार्वजनिक हैं। कार्यान्वयन सभी सदस्यों को लागू करना है।
  • Interfaces Decoupling में मदद करते हैं। आप इंटरफ़ेस के पीछे कुछ भी नकल करने के लिए नकली ढांचे का उपयोग कर सकते हैं
  • इंटरफेस आमतौर पर एक तरह का व्यवहार इंगित करता है
  • इंटरफेस कार्यान्वयन एक दूसरे से decoupled / अलग कर रहे हैं

बेस कक्षाएं

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

जुआन,

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

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

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

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

तो अगर आप मेरे जैसे सोचते हैं तो आप निश्चित रूप से कहेंगे कि बिल्ली और कुत्ते आईपीटेबल हैं। यह एक विशेषता है जो दोनों से मेल खाती है।

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

कहो मैं सभी पशु वर्गों को इकट्ठा करना चाहता हूं और उन्हें अपने सन्दूक कंटेनर में रखना चाहता हूं।

या क्या उन्हें स्तनधारियों की आवश्यकता है? शायद हमें किसी प्रकार का क्रॉस पशु दुग्ध कारखाना चाहिए?

क्या उन्हें भी एक साथ जोड़ने की ज़रूरत है? क्या यह सिर्फ इतना पता है कि वे दोनों आईपीएटेबल हैं?

मुझे अक्सर एक वर्ग की पदानुक्रम प्राप्त करने की इच्छा महसूस होती है जब मुझे वास्तव में केवल एक वर्ग की आवश्यकता होती है। मैं इसे किसी दिन प्रत्याशा में करता हूं, मुझे इसकी आवश्यकता हो सकती है और आमतौर पर मैं कभी नहीं करता। यहां तक ​​कि जब भी मैं करता हूं, मुझे आमतौर पर लगता है कि मुझे इसे ठीक करने के लिए बहुत कुछ करना है। ऐसा इसलिए है क्योंकि मैं जो प्रथम श्रेणी बना रहा हूं वह कुत्ता नहीं है, मैं भाग्यशाली नहीं हूं, बल्कि प्लैटिपस है। अब मेरी पूरी कक्षा पदानुक्रम विचित्र मामले पर आधारित है और मेरे पास बहुत बर्बाद कोड है।

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


Conceptually, an Interface is used to formally and semi-formally define a set of methods that an object will provide. Formally means a set of method names and signatures, semi-formally means human readable documentation associated with those methods. Interfaces are only descriptions of an API (after all, API stands for Application Programmer Interface ), they can't contain any implementation, and it's not possible to use or run an Interface. They only make explicit the contract of how you should interact with an object.

Classes provide an implementation, they can declare that they implement zero, one or more Interfaces. If a Class is intended to be inherited, the convention is to prefix the Class name with "Base".

There is a distinction between a Base Class and an Abstract Base Classes (ABC). ABCs mix interface and implementation together. Abstract outside of computer programming means "summary", that is "Abstract == Interface". An Abstract Base Class can then describe both an interface, as well as an empty, partial or complete implementation that is intended to be inherited.

Opinions on when to use Interfaces versus Abstract Base Classes versus just Classes is going to vary wildly based on both what you are developing, and which language you are developing in. Interfaces are often associated only with statically typed languages such as Java or C#, but dynamically typed languages can also have Interfaces and Abstract Base Classes. In Python for example, the distinction is made clear between a Class, which declares that it implements an Interface, and an object, which is an instance of a Class, and is said to provide that Interface. It's possible in a dynamic language that two objects that are both instances of the same Class, can declare that they provide completely different interfaces. In Python this is only possible for object attributes, while methods are shared state between all objects of a Class. However in Ruby, objects can have per-instance methods, so it's possible that the Interface between two objects of the same Class can vary as much as the programmer desires (however, Ruby doesn't have any explicit way of declaring Interfaces).

In dynamic languages the Interface to an object is often implicitly assumed, either by introspecting an object and asking it what methods it provides (Look Before You Leap) or preferably by simply attempting to use the desired Interface on an object and catching exceptions if the object doesn't provide that Interface (Easier to Ask Forgiveness than Permission). This can lead to "false positives" where two Interfaces have the same method name but are semantically different, however the trade-off is that your code is more flexible since you don't need to over specify up-front to anticipate all possible uses of your code.


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

Krzysztof Cwalina पृष्ठ 81 पर कहते हैं:

.NET Framework के तीन संस्करणों के दौरान, मैंने हमारी टीम पर कुछ डेवलपर्स के साथ इस दिशानिर्देश के बारे में बात की है। उनमें से कई, जो प्रारंभ में दिशानिर्देशों से असहमत थे, ने कहा है कि उन्हें कुछ एपीआई इंटरफ़ेस के रूप में भेजने पर खेद है। मैंने एक ऐसे मामले के बारे में भी नहीं सुना है जिसमें किसी को खेद है कि उन्होंने एक वर्ग भेज दिया है।

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


आइए कुत्ते और बिल्ली वर्ग का अपना उदाहरण लें, और चलिए सी # का उपयोग करके चित्रित करते हैं:

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

public abstract class Mammal

इस बेस क्लास में शायद डिफ़ॉल्ट विधियां होंगी जैसे कि:

  • चारा
  • दोस्त

जिनमें से सभी व्यवहार हैं जो कि प्रजातियों के बीच समान कार्यान्वयन कम या कम हैं। इसे परिभाषित करने के लिए आपके पास होगा:

public class Dog : Mammal
public class Cat : Mammal

अब मान लीजिए कि अन्य स्तनधारियां हैं, जिन्हें हम आम तौर पर एक चिड़ियाघर में देखेंगे:

public class Giraffe : Mammal
public class Rhinoceros : Mammal
public class Hippopotamus : Mammal

यह अभी भी वैध होगा क्योंकि कार्यक्षमता के मूल पर Feed() और Mate() अभी भी वही होंगे।

हालांकि, जिराफ, rhinoceros, और hippos बिल्कुल जानवर नहीं हैं कि आप पालतू जानवरों को बाहर कर सकते हैं। यही वह जगह है जहां एक इंटरफ़ेस उपयोगी होगा:

public interface IPettable
{
    IList<Trick> Tricks{get; set;}
    void Bathe();
    void Train(Trick t);
}

उपरोक्त अनुबंध के लिए कार्यान्वयन बिल्ली और कुत्ते के बीच समान नहीं होगा; अपने कार्यान्वयन को एक अमूर्त वर्ग में विरासत में रखने के लिए एक बुरा विचार होगा।

आपके कुत्ते और बिल्ली परिभाषाओं को अब इस तरह दिखना चाहिए:

public class Dog : Mammal, IPettable
public class Cat : Mammal, IPettable

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

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


I usually don't implement either until I need one. I favor interfaces over abstract classes because that gives a little more flexibility. If there's common behavior in some of the inheriting classes I move that up and make an abstract base class. I don't see the need for both, since they essentially server the same purpose, and having both is a bad code smell (imho) that the solution has been over-engineered.


जब मैंने पहली बार ऑब्जेक्ट उन्मुख प्रोग्रामिंग के बारे में सीखना शुरू किया, तो मैंने सामान्य व्यवहार साझा करने के लिए विरासत का उपयोग करने की आसान और संभवतः सामान्य गलती की - यहां तक ​​कि उस व्यवहार को वस्तु की प्रकृति के लिए आवश्यक नहीं था।

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

हालांकि, पालतू होने योग्य इन वस्तुओं में से किसी की प्रकृति का हिस्सा नहीं है। उनकी प्रकृति के लिए आवश्यक बहुत अधिक महत्वपूर्ण अवधारणाएं हैं - प्रेमिका एक व्यक्ति है, कार एक भूमि वाहन है, बिल्ली एक स्तनपायी है ...

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

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

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


मेरे पास एक मोटा नियम है

कार्यक्षमता: सभी भागों में अलग होने की संभावना: इंटरफ़ेस।

डेटा, और कार्यक्षमता, भागों ज्यादातर एक ही होंगे, भागों अलग: अमूर्त वर्ग।

डेटा, और कार्यक्षमता, वास्तव में काम कर रही है, अगर केवल मामूली परिवर्तन के साथ विस्तारित: सामान्य (ठोस) वर्ग

डेटा और कार्यक्षमता, कोई बदलाव नहीं किया गया: अंतिम संशोधक के साथ सामान्य (ठोस) वर्ग।

डेटा, और शायद कार्यक्षमता: केवल पढ़ने के लिए: enum सदस्यों।

यह बहुत मोटा और तैयार है और बिल्कुल सख्ती से परिभाषित नहीं है, लेकिन इंटरफेस से एक स्पेक्ट्रम है जहां सब कुछ enums में बदलना है, जहां सबकुछ केवल पढ़ने-योग्य फ़ाइल की तरह तय किया जाता है।


An inheritor of a base class should have an "is a" relationship. Interface represents An "implements a" relationship. So only use a base class when your inheritors will maintain the is a relationship.


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

कुछ मामलों में, आप पाते हैं कि आपकी प्राथमिक वस्तुओं को इंटरफेस की आवश्यकता नहीं है, अगर सभी उत्परिवर्तनीय व्यवहार सहायक वस्तुओं में परिभाषित किया गया है।

तो आईपेट या पेटबेस के बजाय, आप एक पालतू जानवर के साथ समाप्त हो सकते हैं जिसमें IFurBehavior पैरामीटर है। IFurBehavior पैरामीटर PetFactory के CreateDog () विधि द्वारा सेट किया गया है। यह पैरामीटर है जिसे शेड () विधि के लिए बुलाया जाता है।

यदि आप ऐसा करते हैं तो आप पाएंगे कि आपका कोड अधिक लचीला है और आपकी अधिकांश साधारण वस्तुएं बहुत ही बुनियादी प्रणाली-व्यापी व्यवहार से निपटती हैं।

मैं इस पैटर्न को कई विरासत भाषाओं में भी अनुशंसा करता हूं।


Another option to keep in mind is using the "has-a" relationship, aka "is implemented in terms of" or "composition." Sometimes this is a cleaner, more flexible way to structure things than using "is-a" inheritance.

It may not make as much sense logically to say that Dog and Cat both "have" a Pet, but it avoids common multiple inheritance pitfalls:

public class Pet
{
    void Bathe();
    void Train(Trick t);
}

public class Dog
{
    private Pet pet;

    public void Bathe() { pet.Bathe(); }
    public void Train(Trick t) { pet.Train(t); }
}

public class Cat
{
    private Pet pet;

    public void Bathe() { pet.Bathe(); }
    public void Train(Trick t) { pet.Train(t); }
}

Yes, this example shows that there is a lot of code duplication and lack of elegance involved in doing things this way. But one should also appreciate that this helps to keep Dog and Cat decoupled from the Pet class (in that Dog and Cat do not have access to the private members of Pet), and it leaves room for Dog and Cat to inherit from something else--possibly the Mammal class.

Composition is preferable when no private access is required and you don't need to refer to Dog and Cat using generic Pet references/pointers. Interfaces give you that generic reference capability and can help cut down on the verbosity of your code, but they can also obfuscate things when they are poorly organized. Inheritance is useful when you need private member access, and in using it you are committing yourself to highly coupling your Dog and Cat classes to your Pet class, which is a steep cost to pay.

Between inheritance, composition, and interfaces there is no one way that is always right, and it helps to consider how all three options can be used in harmony. Of the three, inheritance is typically the option that should be used the least often.


यहां इंटरफ़ेस और बेस क्लास का मूल और सरल definiton है:

  • बेस क्लास = ऑब्जेक्ट विरासत।
  • इंटरफ़ेस = कार्यात्मक विरासत।

चियर्स


इंटरफेस पर बेस क्लासेस के मामले को Submain .NET कोडिंग दिशानिर्देशों में अच्छी तरह से समझाया गया था:

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

चूंकि इंटरफेस कार्यान्वयन विरासत का समर्थन नहीं करते हैं, इसलिए वर्गों पर लागू पैटर्न इंटरफेस पर लागू नहीं होता है। एक इंटरफ़ेस में कोई विधि जोड़ना बेस क्लास में एक सार विधि जोड़ने के बराबर है; इंटरफ़ेस लागू करने वाली कोई भी कक्षा टूट जाएगी क्योंकि कक्षा नई विधि को लागू नहीं करती है। इंटरफेस निम्नलिखित स्थितियों में उपयुक्त हैं:

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

Regarding C#, in some senses interfaces and abstract classes can be interchangeable. However, the differences are: i) interfaces cannot implement code; ii) because of this, interfaces cannot call further up the stack to subclass; and iii) only can abstract class may be inherited on a class, whereas multiple interfaces may be implemented on a class.





static-typing