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


767

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

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

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


11
बस एक बिंदु जो मुझे लगता है कि आपको ध्यान में रखना चाहिए - इंटरफेस में कई सीमाएं हो सकती हैं जो आपको बहुत देर के चरणों तक पता नहीं हो सकती हैं। उदाहरण के लिए, .NET के साथ आप एक इंटरफ़ेस सदस्य चर को क्रमबद्ध नहीं कर सकते हैं, इसलिए यदि आपके पास एक वर्ग चिड़ियाघर और IAnimals का एक सदस्य चर सरणी है, तो आप चिड़ियाघर को अनुक्रमित नहीं कर पाएंगे (और इसका मतलब है कि वेबसर्विस या अन्य चीजों को लिखना जो क्रमबद्धता की आवश्यकता होगी। एक दर्द)।
सिन्धर्सको

1
यह सवाल इंटरफेस की अवधारणा को समझने में मदद कर सकता है। stackoverflow.com/q/8531292/1055241
gprathour

मैं बस उत्सुक हूँ। मैं सीएलआर के माध्यम से सी # के माध्यम से निम्नलिखित अंश में मिला I tend to prefer using the interface technique over the base type technique because the base type technique doesn’t allow the developer to choose the base type that works best in a particular situation.:। मैं यह नहीं समझ सकता कि अंश में क्या अर्थ है। हम कुछ प्रकार के आधार बना सकते हैं और उनमें से किसी के लिए एक व्युत्पन्न प्रकार बना सकते हैं, इसलिए एक डेवलपर आधार प्रकार चुन सकता है। क्या कोई समझा सकता है, कृपया, मुझे क्या याद आ रहा है? मेरा मानना ​​है कि यह इस सवाल का एक हिस्सा हो सकता है। या मुझे विशिष्ट अंश के बारे में एक और पोस्ट करना चाहिए?
qqqqqqq

जवाबों:


501

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

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

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()अभी भी वही होगा।

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

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

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

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

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

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

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


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

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

10
@ डेविड टाउचे, हालांकि मैंने बेहतर चित्रण के लिए यह बताया कि एक इंटरफ़ेस क्या है और उसकी समझ के लिए एक अमूर्त वर्ग क्या है। एक कुत्ते और एक बिल्ली एक कठोर आवश्यकता प्रतीत नहीं होती है!
जॉन लीमजप

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

14
इसके अलावा, एक इंटरफ़ेस पालतू चट्टान के लिए अनुमति देता है, इसे स्नान करने और चाल सिखाने की अनुमति देता है, लेकिन खिलाने और संभोग का समर्थन नहीं किया जाएगा क्योंकि यह एक चट्टान के लिए हास्यास्पद होगा।
एक्लक्स

146

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

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

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

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

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

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

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

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

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

पुनश्च: पुस्तक खरीदें। यह बहुत अधिक विस्तृत है।


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

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

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

118

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

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

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


10
सभी उत्तरों में से, यह स्पष्टता के नुकसान के बिना संक्षिप्तता का सबसे अच्छा मिश्रण देता है
मैट विल्को

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

1
@ अजीब बात है कि आप लिखते हैं कि क्योंकि स्क्रीन इंटरफेस के माध्यम से कार्यान्वित की जाती हैं - वीजीए, एचडीएमआई आदि
कोन्स्टेंटिन

सिर्फ इसलिए कि यह OOP है, हमें वास्तविक जीवन परिदृश्यों का पालन करने के लिए अपनी कल्पना को फैलाना होगा। यह हमेशा लागू नहीं होता है।
क्रिस्मोग्राम

110

आधुनिक शैली IPet और PetBase को परिभाषित करने के लिए है ।

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

लेकिन आधार कक्षाएं सरल कार्यान्वयन और सामान्य उपयोगिताओं के लिए उपयोगी हैं। इसलिए समय और कोड बचाने के लिए एक सार आधार वर्ग प्रदान करें।


अपना केक लो और इसे भी खा लो!
डैरेन कोप्प

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

27
यहाँ कुछ भी "आधुनिक" नहीं है। एक ही एपीआई के साथ बेस क्लास और इंटरफ़ेस केवल बेमानी है। आप कुछ मामलों में इस दृष्टिकोण का उपयोग कर सकते हैं लेकिन आपको सामान्यीकरण नहीं करना चाहिए!
सिमेंटेक

3
दूसरे समर्थित उत्तर के लिए सबसे अधिक समर्थित टिप्पणी वास्तव में दिलचस्प, स्वयं उत्तर से असहमत है। मुझे कहना होगा कि मुझे इंटरफ़ेस और बेस क्लास के सह-अस्तित्व के कई उदाहरण दिखाई देते हैं। इस अर्थ में यह "आधुनिक" तरीका है। उदाहरण के लिए, MVVM पैटर्न में, वास्तव में ViewModelBase क्लास है जो INotifyPropertyChanged को लागू करता है। लेकिन जब मेरे सहकर्मी ने मुझसे पूछा कि मेरे पास बेस क्लास क्यों है, तो हर दृश्य मॉडल में इंटरफ़ेस को लागू करने के बजाय, मुझे नहीं पता कि उसे कैसे
मनाऊं

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

63

इंटरफेस

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

आधार वर्ग

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

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

59

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

द गैंग ऑफ़ फोर ने अपनी पुस्तक में कहा है "क्योंकि विरासत अपने माता-पिता के कार्यान्वयन के विवरण के लिए एक उपवर्ग को उजागर करती है, यह अक्सर कहा जाता है कि 'विरासत टूटता है।" मैं इसे सच मानता हूं।


Yeesh। व्यक्तिगत रूप से, मेरा मानना ​​है कि यह पीछे की तरफ गधा है। इंटरफेस में एक प्रकार के लिए नंगे न्यूनतम कार्यक्षमता होनी चाहिए, और आधार वर्गों को एक समृद्ध रूपरेखा प्रदान करनी चाहिए, जिस पर अनुकूलन बनाया जा सकता है। इसे एक इंटरफेस में रखें और आपने इसे लागू करना बहुत कठिन बना दिया है।

किसी ने नहीं कहा कि आपके इंटरफेस को विशाल होने की आवश्यकता है। छोटे, कई इंटरफेस और अमीर आधार वर्ग एक महान एपीआई बनाते हैं।
किल्होफर सफ़र 11'08

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

@ किलहोफ़र "इंटरफेस अधिकतम लचीलेपन और सीमाओं के प्रकारों की पोर्टेबिलिटी की अनुमति देता है" कृपया इस कथन को विस्तृत करें।
JAVA

49

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

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

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

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


19

जुआन,

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

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

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

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

इसलिए यदि आप मेरी तरह सोचते हैं तो आप निश्चित रूप से कहेंगे कि कैट और डॉग IPettable हैं। यह एक ऐसा लक्षण है जो उन दोनों से मेल खाता है।

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

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

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

क्या उन्हें भी एक साथ जुड़ने की जरूरत है? क्या यह जानना पर्याप्त है कि वे दोनों ही IPettable हैं?

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

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


18

यहाँ इंटरफ़ेस और आधार वर्ग की मूल और सरल परिभाषा है:

  • आधार वर्ग = वस्तु वंशानुक्रम।
  • इंटरफ़ेस = कार्यात्मक विरासत।

चियर्स


12

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

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

तो IPet या PetBase के बजाय, आप एक Pet के साथ समाप्त हो सकते हैं, जिसमें IFurBehavior पैरामीटर है। IFurBehavior पैरामीटर पेटफैक्ट्री के CreateDog () विधि द्वारा सेट किया गया है। यह यह पैरामीटर है जिसे शेड () विधि के लिए कहा जाता है।

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

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


12

यह जावा विश्व लेख में अच्छी तरह से समझाया गया है ।

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

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

सार कक्षाएं मैं किसी और चीज के लिए एक आधार के रूप में उपयोग करता हूं।

निम्नलिखित उपरोक्त लेख JavaWorld.com लेख, लेखक टोनी सिंटेस, 04/20/01 से एक उद्धरण है


इंटरफ़ेस बनाम सार वर्ग

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

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

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

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

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

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

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

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


2
+1। "प्रकार की पहचान के लिए विरासत पर भरोसा करना खतरनाक है; यह आपको एक विशेष विरासत पदानुक्रम में बंद कर देता है।" वह वाक्य पूरी तरह से इंटरफेस पसंद करने के लिए मेरे कारणों का वर्णन करता है।
इंजीनियर

और इसके अलावा, विस्तार करने के बजाय, अपने इंटरफ़ेस की प्रत्येक विधि के पीछे कार्यान्वयन की रचना करें।
इंजीनियर

10

यह भी ध्यान रखें कि OO ( ब्लॉग देखें ) में बह न जाएं और हमेशा आवश्यक व्यवहार के आधार पर ऑब्जेक्ट्स को मॉडल करें, यदि आप एक ऐसा ऐप डिजाइन कर रहे हैं जहां आपके लिए आवश्यक एकमात्र व्यवहार एक सामान्य नाम और एक जानवर के लिए प्रजातियां थीं तो आपको केवल आवश्यकता होगी दुनिया के हर संभव जानवर के लिए लाखों वर्गों के बजाय, नाम के लिए एक संपत्ति के साथ एक वर्ग पशु।


10

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

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

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

डेटा और कार्यक्षमता, वास्तव में काम कर रहे हैं, अगर केवल थोड़े से बदलाव के साथ बढ़ाया जाता है: साधारण (ठोस) वर्ग

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

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

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


7

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

सार वर्ग शॉर्टकट हैं। क्या ऐसी चीजें हैं जो पेटबेस के सभी डेरिवेटिव साझा करते हैं जिन्हें आप एक बार कोड कर सकते हैं और साथ कर सकते हैं? यदि हाँ, तो यह एक अमूर्त वर्ग का समय है।

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

सार कक्षाओं में कई इंटरफेस हो सकते हैं। आपका पेटबेस सार वर्ग IPet (पालतू जानवरों के मालिक) और IDigestion (पालतू जानवर खाते हैं, या कम से कम उन्हें चाहिए) को लागू कर सकता है। हालांकि, पेटबेस शायद IMammal को लागू नहीं करेगा, क्योंकि सभी पालतू जानवर स्तनधारी नहीं हैं और सभी स्तनधारी पालतू जानवर नहीं हैं। आप एक MammalPetBase जोड़ सकते हैं जो पेटबेस को बढ़ाता है और IMammal जोड़ता है। फिशबेस में पेटबेस हो सकता है और इफिश को जोड़ सकता है। इफिश में इंटरफेस के रूप में इस्विम और आईउंडरवॉटरब्रिज होगा।

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


7

स्रोत : http://jasonroell.com/2014/12/09/interfaces-vs-abstract-classes-what-should-you-use/

C # एक अद्भुत भाषा है जो पिछले 14 वर्षों में परिपक्व और विकसित हुई है। यह हमारे लिए डेवलपर्स के लिए बहुत अच्छा है क्योंकि एक परिपक्व भाषा हमें भाषा सुविधाओं की अधिकता प्रदान करती है जो हमारे निपटान में हैं।

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

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

यह सब अच्छी तरह से और अच्छा है और कोड के महान पुन: उपयोग के लिए प्रदान करता है और DRY (अपने आप को दोहराएं नहीं) सॉफ्टवेयर विकास के सिद्धांत का पालन करता है। जब आपके पास "संबंध" है तब सार कक्षाएं उपयोग करने के लिए महान हैं।

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

public abstract class Dog
{
      public virtual void Bark()
      {
        Console.WriteLine("Base Class implementation of Bark");
      }
}

public class GoldenRetriever : Dog
{
   // the Bark method is inherited from the Dog class
}

public class Poodle : Dog
{
  // here we are overriding the base functionality of Bark with our new implementation
  // specific to the Poodle class
  public override void Bark()
  {
     Console.WriteLine("Poodle's implementation of Bark");
  }
}

// Add a list of dogs to a collection and call the bark method.

void Main()
{
    var poodle = new Poodle();
    var goldenRetriever = new GoldenRetriever();

    var dogs = new List<Dog>();
    dogs.Add(poodle);
    dogs.Add(goldenRetriever);

    foreach (var dog in dogs)
    {
       dog.Bark();
    }
}

// Output will be:
// Poodle's implementation of Bark
// Base Class implementation of Bark

// 

जैसा कि आप देख सकते हैं, यह आपके कोड DRY को रखने और बेस क्लास कार्यान्वयन के लिए अनुमति देने का एक शानदार तरीका होगा, जब किसी भी प्रकार के विशेष मामले के कार्यान्वयन के बजाय डिफ़ॉल्ट बार्क पर भरोसा कर सकते हैं। GoldenRetriever, Boxer, Lab जैसी कक्षाएं सभी "डिफ़ॉल्ट" (बास वर्ग) बार्क को बिना किसी शुल्क के विरासत में दे सकती थीं, क्योंकि वे डॉग अमूर्त वर्ग को लागू करती हैं।

लेकिन मुझे यकीन है कि आप पहले से ही जानते थे।

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

अब इसका क्या मतलब है? ठीक है, उदाहरण के लिए: एक मानव एक बतख नहीं है ... और एक बतख मानव नहीं है। काफी सामान्य। हालांकि, एक बतख और एक मानव दोनों के पास तैरने की "क्षमता" है (यह देखते हुए कि मानव ने 1 ग्रेड में अपने तैराकी सबक पास किए :))। इसके अलावा, चूंकि एक बतख एक मानव या इसके विपरीत नहीं है, यह एक "अहसास" नहीं है, बल्कि एक "सक्षम" संबंध है और हम इसका वर्णन करने के लिए एक इंटरफ़ेस का उपयोग कर सकते हैं:

// Create ISwimable interface
public interface ISwimable
{
      public void Swim();
}

// Have Human implement ISwimable Interface
public class Human : ISwimable

     public void Swim()
     {
        //Human's implementation of Swim
        Console.WriteLine("I'm a human swimming!");
     }

// Have Duck implement ISwimable interface
public class Duck: ISwimable
{
     public void Swim()
     {
          // Duck's implementation of Swim
          Console.WriteLine("Quack! Quack! I'm a Duck swimming!")
     }
}

//Now they can both be used in places where you just need an object that has the ability "to swim"

public void ShowHowYouSwim(ISwimable somethingThatCanSwim)
{
     somethingThatCanSwim.Swim();
}

public void Main()
{
      var human = new Human();
      var duck = new Duck();

      var listOfThingsThatCanSwim = new List<ISwimable>();

      listOfThingsThatCanSwim.Add(duck);
      listOfThingsThatCanSwim.Add(human);

      foreach (var something in listOfThingsThatCanSwim)
      {
           ShowHowYouSwim(something);
      }
}

 // So at runtime the correct implementation of something.Swim() will be called
 // Output:
 // Quack! Quack! I'm a Duck swimming!
 // I'm a human swimming!

ऊपर दिए गए कोड की तरह इंटरफेस का उपयोग करने से आप किसी वस्तु को उस विधि से पारित कर सकते हैं जो कुछ करने के लिए "सक्षम" है। कोड यह परवाह नहीं करता है कि यह कैसे करता है ... यह सब जानता है कि यह उस वस्तु पर स्विम विधि को कॉल कर सकता है और उस वस्तु को पता चल जाएगा कि कौन सा व्यवहार उसके प्रकार के आधार पर रन-टाइम पर होता है।

एक बार फिर, यह आपके कोड को DRY में बने रहने में मदद करता है, ताकि आपको एक ही कोर फंक्शन (ShowHowHumanSwims (human), ShowHowDuckSwims (duck), आदि) को प्रीफॉर्म करने के लिए कई तरीके लिखने न पड़े।

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

सारांश:

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

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

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

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

एक और टिप यह है कि यदि आप कार्यक्षमता के छोटे, संक्षिप्त बिट्स विकसित कर रहे हैं, तो इंटरफेस का उपयोग करें। यदि आप बड़ी कार्यात्मक इकाइयाँ डिज़ाइन कर रहे हैं, तो एक सार वर्ग का उपयोग करें।

आशा है कि यह कुछ लोगों के लिए चीजों को साफ करता है!

यदि आप किसी भी बेहतर उदाहरण के बारे में सोच सकते हैं या कुछ इंगित करना चाहते हैं, तो कृपया नीचे टिप्पणी में ऐसा करें!


6

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

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

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

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

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

5

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


4

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

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

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

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

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

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


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

4

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

Rationale, विचार करने के लिए मुख्य बिंदु [दो पहले से ही यहाँ उल्लेख किया गया है] हैं:

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

[१] इसमें अधिक कोड शामिल है, लेकिन अगर संक्षिप्तता आपकी प्राथमिक चिंता है, तो आपको संभवतः पहली जगह में जावा से बचना चाहिए था!

[२] जोशुआ बलोच, प्रभावी जावा, आइटम १६-१ Blo।

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


3

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


3

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

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

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


3

ध्यान में रखने के लिए एक और विकल्प "है-एक" संबंध, उर्फ ​​"का उपयोग" या "रचना के संदर्भ में लागू किया गया है। कभी-कभी यह एक क्लीनर है, चीजों का उपयोग करने की तुलना में संरचना को अधिक लचीला तरीका है "-एक" विरासत।

यह कहने के लिए तार्किक रूप से अधिक समझदारी नहीं हो सकती है कि डॉग और कैट दोनों के पास "एक पालतू जानवर" है, लेकिन यह आम बहु विरासत वाले नुकसान से बचता है:

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); }
}

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

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

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


3

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

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

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

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

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

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


2

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

बेस क्लास को लागू करने के लिए मौजूदा तरीकों की आवश्यकता override(या new) है। यह उन्हें आभासी तरीके बनाता है जिसका अर्थ है कि आपको इस बात से सावधान रहना होगा कि आप ऑब्जेक्ट इंस्टेंस का उपयोग कैसे करते हैं।

अंत में, .NET की एकल विरासत मुझे मार देती है। एक भोला उदाहरण: कहते हैं कि आप एक उपयोगकर्ता नियंत्रण बना रहे हैं, ताकि आपको विरासत में मिलेUserControl । लेकिन, अब आप विरासत से भी बाहर हो गए हैं PetBase। यह आपको PetBaseइसके बजाय एक वर्ग के सदस्य बनाने के लिए पुनर्गठित करने के लिए मजबूर करता है ।


2

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


2

सी # के संबंध में, कुछ इंद्रियों में इंटरफेस और अमूर्त कक्षाएं विनिमेय हो सकती हैं। हालाँकि, अंतर हैं: i) इंटरफेस कोड लागू नहीं कर सकते हैं; ii) इस वजह से, इंटरफेस उप-वर्ग के लिए स्टैक को आगे नहीं बुला सकते हैं; और iii) केवल अमूर्त वर्ग एक वर्ग को विरासत में मिल सकता है, जबकि एक वर्ग पर कई इंटरफेस लागू हो सकते हैं।


2

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


2

मैंने पाया है कि इंटरफ़ेस का एक पैटर्न> सार> कंक्रीट निम्नलिखित उपयोग के मामले में काम करता है:

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)

अमूर्त वर्ग कंक्रीट कक्षाओं की डिफ़ॉल्ट साझा विशेषताओं को परिभाषित करता है, फिर भी इंटरफ़ेस को लागू करता है। उदाहरण के लिए:

public interface IPet{

    public boolean hasHair();

    public boolean walksUprights();

    public boolean hasNipples();
}

अब, चूंकि सभी स्तनधारियों में बाल और निप्पल होते हैं (AFAIK, आई एम नॉट जूलॉजिस्ट), हम इसे सार बेस क्लास में रोल कर सकते हैं

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}

और फिर ठोस वर्ग केवल यह परिभाषित करते हैं कि वे सीधे चलते हैं।

public class Ape extends Mammal(){

    @override
    public walksUpright(return true)
}

public class Catextends Mammal(){

    @override
    public walksUpright(return false)
}

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

इस मामले में, अमूर्त सिर्फ ठोस हो सकता है; हालांकि, अमूर्त पदनाम इस बात पर जोर देने में मदद करता है कि इस पैटर्न को नियोजित किया जा रहा है।


1

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


1

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

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

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