इंटरफेस - क्या बात है?


269

इंटरफेस का कारण वास्तव में मुझे बाहर निकालता है। जो मैं समझता हूं, वह गैर-मौजूद बहु-विरासत के लिए एक तरह का काम है जो C # में मौजूद नहीं है (या इसलिए मुझे बताया गया था)।

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

नीचे दिए गए उदाहरण में, स्टैक ओवरफ्लो पर एक अलग सी # इंटरफेस थ्रेड से लिया गया है, मैं बस एक बेस क्लास बनाऊंगा जिसे इंटरफेस के बजाय पिज्जा कहा जाता है।

आसान उदाहरण (एक अलग स्टैक ओवरफ्लो योगदान से लिया गया)

public interface IPizza
{
    public void Order();
}

public class PepperoniPizza : IPizza
{
    public void Order()
    {
        //Order Pepperoni pizza
    }
}

public class HawaiiPizza : IPizza
{
    public void Order()
    {
        //Order HawaiiPizza
    }
}

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

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


1
इसके अलावा इंटरफेस structप्रकारों के लिए विरासत स्थापित करने में मदद करते हैं।
ja72

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

जवाबों:


176

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

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

पायथन सांख्यिकीय रूप से टाइप नहीं किया जाता है, इसलिए प्रकारों को रखा जाता है और रनटाइम पर देखा जाता है। तो आप Order()किसी भी ऑब्जेक्ट पर एक विधि को कॉल करने का प्रयास कर सकते हैं । रनटाइम तब तक खुश रहता है जब तक ऑब्जेक्ट में ऐसी विधि होती है और शायद सिर्फ झाड़ियाँ और कहते हैं »मेह।« अगर यह नहीं होता है। C # में ऐसा नहीं है। कंपाइलर सही कॉल करने के लिए जिम्मेदार है और अगर यह सिर्फ कुछ यादृच्छिक objectहै कंपाइलर अभी तक नहीं जानता है कि रनटाइम के दौरान उदाहरण में वह विधि होगी या नहीं। संकलक के दृष्टिकोण से यह अमान्य है क्योंकि यह इसे सत्यापित नहीं कर सकता है। (आप ऐसी चीजों को प्रतिबिंब या के साथ कर सकते हैंdynamic कीवर्ड के , लेकिन यह अभी थोड़ी दूर है, मुझे लगता है।)

यह भी ध्यान दें कि सामान्य अर्थों में एक इंटरफेस के लिए जरूरी नहीं है कि वह C # हो interface, यह एक अमूर्त वर्ग या सामान्य वर्ग भी हो सकता है (जो काम में आ सकता है, यदि सभी उपवर्गों को कुछ सामान्य कोड साझा करने की आवश्यकता हो - ज्यादातर मामलों में , हालांकि, interfaceपर्याप्त)।


1
+1, हालांकि मैं यह नहीं कहूंगा कि इंटरफ़ेस (अनुबंध के अर्थ में) एक सार या सामान्य वर्ग हो सकता है।
ग्रू

3
मुझे लगता है कि आप कुछ मिनटों में इंटरफेस को समझने की उम्मीद नहीं कर सकते हैं। मुझे लगता है कि अगर आपके पास ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग अनुभव का वर्ष नहीं है, तो इंटरफेस को समझना उचित नहीं है। आप पुस्तकों में कुछ लिंक जोड़ सकते हैं। मेरा सुझाव है: .NET में निर्भरता इंजेक्शन जो वास्तव में कितना गहरा छेद है, केवल एक सौम्य परिचय नहीं है।
नॉट

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

1
ठीक है, तो आपका प्रश्न बन जाता है: "गतिशील रूप से टाइप की जाने वाली भाषाओं में प्रोग्राम करने के लिए आसान होने पर" सांख्यिकीय रूप से टाइप की गई भाषाओं का उपयोग क्यों करें? "। हालांकि मैं उस सवाल का जवाब देने के लिए विशेषज्ञ नहीं हूं, मैं यह कहने के लिए उद्यम कर सकता हूं कि प्रदर्शन निर्णायक निर्णय है। जब पायथन ऑब्जेक्ट पर कॉल किया जाता है, तो प्रक्रिया को रन टाइम के दौरान तय करना होगा कि क्या उस ऑब्जेक्ट में "ऑर्डर" नामक एक विधि है, जबकि यदि आप कॉल को C # ऑब्जेक्ट बनाते हैं, तो यह पहले से ही स्थापित है कि यह उस विधि को लागू करता है, और इस तरह के पते पर कॉल किया जा सकता है।
Boluc Papuccuoglu

3
@BolucPapuccuoglu: इससे परे, एक सांख्यिकीय-टाइप की गई वस्तु के साथ यदि कोई व्यक्ति जानता fooहै IWidget, तो एक प्रोग्रामर जो कॉल देख रहा है foo.woozle(), वह दस्तावेज़ीकरण देख सकता है IWidgetऔर यह जान सकता है कि उस पद्धति को क्या करना है । प्रोग्रामर के पास यह जानने का कोई तरीका नहीं हो सकता है कि वास्तविक कार्यान्वयन के लिए कोड कहाँ से आएगा, लेकिन IWidgetइंटरफ़ेस अनुबंध द्वारा पालन करने वाला कोई भी प्रकार fooउस अनुबंध के अनुरूप तरीके से लागू होगा । एक गतिशील भाषा में, इसके विपरीत, इसका कोई स्पष्ट संदर्भ बिंदु नहीं foo.woozle()होना चाहिए कि इसका क्या मतलब होना चाहिए।
सुपरकैट

440

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

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

कोड में यह लिखते समय, तकनीकी रूप से आप बस कर सकते थे

public class Pizza()
{
    public void Prepare(PizzaType tp)
    {
        switch (tp)
        {
            case PizzaType.StuffedCrust:
                // prepare stuffed crust ingredients in system
                break;

            case PizzaType.DeepDish:
                // prepare deep dish ingredients in system
                break;

            //.... etc.
        }
    }
}

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

इसे हल करने का उचित तरीका इंटरफ़ेस का उपयोग करना है। इंटरफ़ेस घोषित करता है कि सभी पिज्जा तैयार किए जा सकते हैं, लेकिन प्रत्येक पिज्जा को अलग तरीके से तैयार किया जा सकता है। इसलिए यदि आपके पास निम्नलिखित इंटरफेस हैं:

public interface IPizza
{
    void Prepare();
}

public class StuffedCrustPizza : IPizza
{
    public void Prepare()
    {
        // Set settings in system for stuffed crust preparations
    }
}

public class DeepDishPizza : IPizza
{
    public void Prepare()
    {
        // Set settings in system for deep dish preparations
    }
}

अब आपके ऑर्डर हैंडलिंग कोड को यह जानने की जरूरत नहीं है कि सामग्री को संभालने के लिए किस प्रकार के पिज्जा ऑर्डर किए गए थे। यह सिर्फ है:

public PreparePizzas(IList<IPizza> pizzas)
{
    foreach (IPizza pizza in pizzas)
        pizza.Prepare();
}

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


11
+1, मुझे इंटरफ़ेस का उपयोग दिखाने के लिए एक सूची का उपयोग करने का उदाहरण पसंद आया।
२०:५० पर डैनियलउंडरवुड

21
अच्छा जवाब है, लेकिन शायद यह स्पष्ट करने के लिए कि क्यों इस मामले में एक इंटरफ़ेस केवल एक अमूर्त वर्ग का उपयोग करने से बेहतर है (इस तरह के एक सरल उदाहरण के लिए, एक अमूर्त वर्ग वास्तव में बेहतर हो सकता है?)
Jez

3
यह सबसे अच्छा जवाब है। थोड़ा टाइपो है या आप कोड को कॉपी और पेस्ट कर सकते हैं। C # इंटरफ़ेस में आप एक्सेस मॉडिफ़ायर घोषित नहीं करते हैं जैसे कि public। तो इंटरफ़ेस के अंदर यह बस होना चाहिएvoid Prepare();
डश

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

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

123

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

(यह पिज्जा सादृश्य खोने जा रहा है, क्योंकि इसके उपयोग की कल्पना करना बहुत आसान नहीं है)

कहें कि आप स्क्रीन पर एक सरल गेम बना रहे हैं और इसमें ऐसे जीव होंगे जिनके साथ आप बातचीत करते हैं।

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

आप इसे शुरू करने के लिए लिख सकते हैं, क्योंकि केवल ट्रोल होने वाले हैं:

// This is our back-end implementation of a troll
class Troll
{
    void Walk(int distance)
    {
        //Implementation here
    }
}

फ़्रंट एंड:

function SpawnCreature()
{
    Troll aTroll = new Troll();

    aTroll.Walk(1);
}

लाइन से दो हफ्ते नीचे, मार्केटिंग तय करती है कि आपको ऑर्क की भी ज़रूरत है, क्योंकि वे ट्विटर पर उनके बारे में पढ़ते हैं, इसलिए आपको कुछ ऐसा करना होगा:

class Orc
{
    void Walk(int distance)
    {
        //Implementation (orcs are faster than trolls)
    }
}

फ़्रंट एंड:

void SpawnCreature(creatureType)
{
    switch(creatureType)
    {
         case Orc:

           Orc anOrc = new Orc();
           anORc.Walk();

          case Troll:

            Troll aTroll = new Troll();
             aTroll.Walk();
    }
}

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

interface ICreature
{
    void Walk(int distance)
}

public class Troll : ICreature
public class Orc : ICreature 

//etc

मोर्चा अंत तब है:

void SpawnCreature(creatureType)
{
    ICreature creature;

    switch(creatureType)
    {
         case Orc:

           creature = new Orc();

          case Troll:

            creature = new Troll();
    }

    creature.Walk();
}

फ्रंट एंड अब केवल इंटरफ़ेस ICreature की परवाह करता है - यह ट्रोल या orc के आंतरिक कार्यान्वयन के बारे में परेशान नहीं है, लेकिन केवल इस तथ्य पर कि वे ICreature को लागू करते हैं।

इस दृष्टि से देखने पर ध्यान देने योग्य एक महत्वपूर्ण बात यह है कि आप आसानी से एक अमूर्त प्राणी वर्ग का उपयोग कर सकते हैं, और इस दृष्टिकोण से, यह एक ही है प्रभाव है।

और आप निर्माण को एक कारखाने में निकाल सकते हैं:

public class CreatureFactory {

 public ICreature GetCreature(creatureType)
 {
    ICreature creature;

    switch(creatureType)
    {
         case Orc:

           creature = new Orc();

          case Troll:

            creature = new Troll();
    }

    return creature;
  }
}

और हमारा अगला छोर तब बन जाएगा:

CreatureFactory _factory;

void SpawnCreature(creatureType)
{
    ICreature creature = _factory.GetCreature(creatureType);

    creature.Walk();
}

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

बी: कहते हैं कि आपके पास कार्यक्षमता है कि केवल कुछ जीव आपके अन्यथा समरूप डेटा संरचना में होंगे , जैसे

interface ICanTurnToStone
{
   void TurnToStone();
}

public class Troll: ICreature, ICanTurnToStone

मोर्चा अंत तब हो सकता है:

void SpawnCreatureInSunlight(creatureType)
{
    ICreature creature;

    switch(creatureType)
    {
         case Orc:

           creature = new Orc();

          case Troll:

            creature = new Troll();
    }

    creature.Walk();

    if (creature is ICanTurnToStone)
    {
       (ICanTurnToStone)creature.TurnToStone();
    }
}

सी: निर्भरता इंजेक्शन के लिए उपयोग

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

public interface ICreatureFactory {
     ICreature GetCreature(string creatureType);
}

हमारा अगला सिरा कंस्ट्रक्टर (आमतौर पर) के माध्यम से इस इंजेक्शन (जैसे एक एमवीसी एपीआई नियंत्रक) हो सकता है:

public class CreatureController : Controller {

   private readonly ICreatureFactory _factory;

   public CreatureController(ICreatureFactory factory) {
     _factory = factory;
   }

   public HttpResponseMessage TurnToStone(string creatureType) {

       ICreature creature = _factory.GetCreature(creatureType);

       creature.TurnToStone();

       return Request.CreateResponse(HttpStatusCode.OK);
   }
}

हमारे DI ढांचे (उदाहरण के लिए Ninject या Autofac) के साथ, हम उन्हें सेट कर सकते हैं ताकि रनटाइम पर CreatureFactory का एक उदाहरण बन जाए जब भी एक निर्माण में एक ICreatureFactory की आवश्यकता हो - यह हमारे कोड को अच्छा और सरल बनाता है।

इसका अर्थ यह भी है कि जब हम अपने नियंत्रक के लिए एक इकाई परीक्षण लिखते हैं, तो हम एक नकली ICreatureFactory प्रदान कर सकते हैं (जैसे कि यदि ठोस कार्यान्वयन के लिए DB पहुँच की आवश्यकता है, हम नहीं चाहते कि हमारी इकाई परीक्षण उस पर निर्भर हो) और आसानी से हमारे नियंत्रक में कोड का परीक्षण करें ।

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

आप तब बी में कार्यक्षमता पाते हैं जो ए में पहले से ही एक विधि को कॉल करने की आवश्यकता है। आप इसे एक ठोस संदर्भ का उपयोग करके नहीं कर सकते क्योंकि आपको एक परिपत्र संदर्भ मिलता है।

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


6
क्या यह कष्टप्रद नहीं है जब आपको एक उत्तर मिलता है जो यह कहना चाह रहा था कि आप क्या थे, लेकिन क्या यह बहुत बेहतर है - stackoverflow.com/a/93998/117215
धान

18
खुशखबरी अब इसका मृत पृष्ठ है और आपका नहीं है :)। अच्छा उदाहरण!
मुहर_05

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

1
यह आपके उदाहरण में मुझे लगता है कि ट्रोल और ऑर्क के लिए अमूर्त बेस क्लास (क्रिएचर?) होने के लिए ICreature बेहतर होगा। तब प्राणियों के बीच किसी भी सामान्य तर्क को वहां लागू किया जा सकता था। जिसका अर्थ है कि आपको ICreature इंटरफ़ेस की आवश्यकता नहीं है ...
Skarsnik

1
@Skarsnik - काफी, जो इस नोट के बारे में है: "इस दृष्टि से देखने पर ध्यान देने योग्य एक महत्वपूर्ण बिंदु यह है कि आप आसानी से एक अमूर्त प्राणी वर्ग का उपयोग कर सकते हैं, और इस दृष्टिकोण से, यह एक ही है प्रभाव।"
धान

33

आपके उदाहरण यहां दिए गए हैं:

public interface IFood // not Pizza
{
    public void Prepare();

}

public class Pizza : IFood
{
    public void Prepare() // Not order for explanations sake
    {
        //Prepare Pizza
    }
}

public class Burger : IFood
{
    public void Prepare()
    {
        //Prepare Burger
    }
}

27

ऊपर दिए गए उदाहरण बहुत मायने नहीं रखते हैं। आप सभी उपर्युक्त उदाहरणों को कक्षाओं का उपयोग करके पूरा कर सकते हैं (सार वर्ग यदि आप चाहते हैं कि यह केवल अनुबंध के रूप में व्यवहार करें ):

public abstract class Food {
    public abstract void Prepare();
}

public class Pizza : Food  {
    public override void Prepare() { /* Prepare pizza */ }
}

public class Burger : Food  {
    public override void Prepare() { /* Prepare Burger */ }
}

आपको इंटरफ़ेस के समान व्यवहार मिलता है। आप List<Food>यह जान सकते हैं कि w / o यह जानने में सक्षम है कि कौन सी कक्षा शीर्ष पर बैठती है।

अधिक पर्याप्त उदाहरण कई उत्तराधिकार होगा:

public abstract class MenuItem {
    public string Name { get; set; }
    public abstract void BringToTable();
}

// Notice Soda only inherits from MenuItem
public class Soda : MenuItem {
    public override void BringToTable() { /* Bring soda to table */ }
}


// All food needs to be cooked (real food) so we add this
// feature to all food menu items
public interface IFood {
    void Cook();
}

public class Pizza : MenuItem, IFood {
    public override void BringToTable() { /* Bring pizza to table */ }
    public void Cook() { /* Cook Pizza */ }
}

public class Burger : MenuItem, IFood {
    public override void BringToTable() { /* Bring burger to table */ }
    public void Cook() { /* Cook Burger */ }
}

तब आप उन सभी का उपयोग कर सकते हैं MenuItemऔर इस बात की परवाह नहीं करते कि वे प्रत्येक विधि कॉल को कैसे संभालते हैं।

public class Waiter {
    public void TakeOrder(IEnumerable<MenuItem> order) 
    {
        // Cook first
        // (all except soda because soda is not IFood)
        foreach (var food in order.OfType<IFood>())
            food.Cook();

        // Bring them all to the table
        // (everything, including soda, pizza and burger because they're all menu items)
        foreach (var menuItem in order)
            menuItem.BringToTable();
    }
}

2
मुझे एक उत्तर खोजने के लिए यहाँ नीचे सभी तरह से स्क्रॉल करना था जो वास्तव में इस सवाल का जवाब देता है कि "इंटरफ़ेस के सार वर्ग का उपयोग क्यों नहीं किया?"। ऐसा लगता है कि यह वास्तव में केवल एकाधिक वंशानुक्रम की कमी को संभालने के लिए है।
सिंटैक्सRules

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

25

सादृश्य के साथ सरल व्याख्या

हल करने की समस्या: बहुरूपता का उद्देश्य क्या है?

सादृश्य: तो मैं एक निर्माण स्थल पर एक अग्रणी हूँ।

ट्रेडमैन निर्माण स्थल पर हर समय चलते हैं। मुझे नहीं पता कि कौन उन दरवाजों से गुजर रहा है। लेकिन मैं मूल रूप से उन्हें बताता हूं कि क्या करना है।

  1. अगर यह एक बढ़ई है तो मैं कहता हूं: लकड़ी का मचान बनाइए।
  2. अगर यह एक प्लम्बर है, तो मैं कहता हूं: "पाइप सेट करें"
  3. यदि यह एक इलेक्ट्रीशियन है, तो मैं कहता हूं, "केबलों को बाहर निकालें, और उन्हें फाइबर ऑप्टिक वाले से बदल दें"।

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

क्या करना है जानने के निहितार्थ:

  • यदि बढ़ई का कोड में परिवर्तन से इस का मतलब है: BuildScaffolding()करने के लिए BuildScaffold()(यानी एक मामूली नाम परिवर्तन) तो मैं भी बुला वर्ग (यानी बदलने के लिए होगा Forepersonवर्ग) के साथ - आप बनाने के लिए होगा दो मूल रूप से करने के बजाय कोड में परिवर्तन ( ) सिर्फ एक। बहुरूपता के साथ आपको (मूल रूप से) केवल एक ही परिणाम प्राप्त करने के लिए एक परिवर्तन करने की आवश्यकता होती है।

  • दूसरी बात यह कि आपको लगातार यह पूछने की जरूरत नहीं होगी: आप कौन हैं? ठीक है ऐसा करो ... तुम कौन हो? ठीक है कि ..... बहुरूपता - यह कोड है कि DRYs, और कुछ स्थितियों में बहुत प्रभावी है:

  • बहुरूपता के साथ आप आसानी से किसी भी मौजूदा कोड को बदलने के बिना पारंपरिक लोगों के अतिरिक्त वर्गों को जोड़ सकते हैं। (यानी एसओएलआईडी डिजाइन सिद्धांतों का दूसरा: ओपन-क्लोज सिद्धांत)।

समाधान

एक परिदृश्य की कल्पना करें, जहां कोई फर्क नहीं पड़ता कि कौन दरवाजे पर चलता है, मैं कह सकता हूं: "काम ()" और वे अपने सम्मान की नौकरियां करते हैं जो वे इसमें माहिर हैं: प्लंबर पाइप से निपटेंगे, और इलेक्ट्रीशियन तारों से निपटेंगे।

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

इसलिए इसके बजाय:

If(electrician) then  electrician.FixCablesAndElectricity() 

if(plumber) then plumber.IncreaseWaterPressureAndFixLeaks() 

मैं ऐसा कुछ कर सकता हूं:

ITradesman tradie = Tradesman.Factory(); // in reality i know it's a plumber, but in the real world you won't know who's on the other side of the tradie assignment.

tradie.Work(); // and then tradie will do the work of a plumber, or electrician etc. depending on what type of tradesman he is. The foreman doesn't need to know anything, apart from telling the anonymous tradie to get to Work()!!

फायदा क्या है?

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


इलस्ट्रेटेड प्रॉब्लम एंड सॉल्यूशन (विदाउट एंड विदाउट इंटरफेस):

कोई इंटरफ़ेस (उदाहरण 1):

उदाहरण 1: इंटरफ़ेस के बिना

कोई इंटरफ़ेस (उदाहरण 2):

उदाहरण 2: इंटरफ़ेस के बिना

इंटरफ़ेस के साथ:

उदाहरण 3: इंटरफ़ेस का उपयोग करने के लाभ

सारांश

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

यदि आपको उपरोक्त में से कोई भी समझ में नहीं आता है या यदि यह एक टिप्पणी में स्पष्ट नहीं है और मैं उत्तर को बेहतर बनाने की कोशिश करूंगा।


4
प्लस एक आदमी है जो एक हूडि में काम में आने के लिए के लिए।
युष

11

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


3
+1 यह सही है, यदि आपने बतख टाइप किया है, तो आपको इंटरफेस की आवश्यकता नहीं है। लेकिन वे मजबूत प्रकार की सुरक्षा को लागू करते हैं।
ग्रू

11

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

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

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


10

उस मामले पर विचार करें जहां आप नियंत्रण नहीं करते हैं या आधार कक्षाएं नहीं हैं।

उदाहरण के लिए विज़ुअल नियंत्रण ले लो। Winforms के लिए .NET में वे सभी बेस क्लास कंट्रोल से इनहेरिट करते हैं, जो पूरी तरह से .NET फ्रेमवर्क में परिभाषित है।

मान लेते हैं कि आप कस्टम नियंत्रण बनाने के व्यवसाय में हैं। आप नए बटन, टेक्स्टबॉक्स, सूची, ग्रिड, व्हाट्सएप का निर्माण करना चाहते हैं और आप उन सभी को अपने नियंत्रण के लिए विशिष्ट विशेषताओं के लिए विशिष्ट बनाना चाहते हैं।

उदाहरण के लिए, आप थीम को संभालने का एक सामान्य तरीका या स्थानीयकरण को संभालने का एक सामान्य तरीका चाहते हैं।

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

इसके बजाय आप Button, TextBox, ListView, GridView, आदि से उतरेंगे और अपना कोड जोड़ेंगे।

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

इंटरफेस दर्ज करें।

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

आप "YourButton" बनाएँगे, बटन से उतरेंगे, और आपको आवश्यक सभी इंटरफेस के लिए समर्थन जोड़ेंगे।

यह आपको निम्नलिखित की तरह कोड लिखने की अनुमति देगा:

foreach (Control ctrl in Controls)
{
    if (ctrl is IMyThemableControl)
        ((IMyThemableControl)ctrl).SetTheme(newTheme);
}

यह इंटरफेस के बिना संभव नहीं होगा, इसके बजाय आपको इस तरह कोड लिखना होगा:

foreach (Control ctrl in Controls)
{
    if (ctrl is MyThemableButton)
        ((MyThemableButton)ctrl).SetTheme(newTheme);
    else if (ctrl is MyThemableTextBox)
        ((MyThemableTextBox)ctrl).SetTheme(newTheme);
    else if (ctrl is MyThemableGridView)
        ((MyThemableGridView)ctrl).SetTheme(newTheme);
    else ....
}

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

4
आहें मुझे पता है, लेकिन वह यहाँ आकस्मिक।
लास वी। कार्लसन जू

7

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

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

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

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


6

गौर करें कि आप C # में कई उत्तराधिकार का उपयोग नहीं कर सकते हैं, और फिर अपने प्रश्न को फिर से देखें।



4

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

आप तो एक कारखाने विधि कॉल: MyInterface i = MyGraphics.getInstance()। फिर, आपके पास एक अनुबंध है, इसलिए आप जानते हैं कि आप किन कार्यों में उम्मीद कर सकते हैं MyInterface। तो, आप कॉल कर सकते हैं i.drawRectangleयाi.drawCube जान हैं कि यदि आप एक लाइब्रेरी को दूसरे के लिए स्वैप करते हैं, तो फ़ंक्शन समर्थित हैं।

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

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

यह .NET में संग्रह के साथ एक महान सौदा किया जाता है, जैसा कि आपको बस उदाहरण के लिए, Listचर का उपयोग करना चाहिए , और चिंता न करें कि यह एक ArrayList या LinkedList था।

जब तक आप इंटरफ़ेस को कोड करते हैं तब तक डेवलपर वास्तविक कार्यान्वयन को बदल सकता है और कार्यक्रम के बाकी हिस्सों को अपरिवर्तित छोड़ दिया जाता है।

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


4

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

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

public void Order();

आपके उल्लेखित कोड के बाद आप कुछ इस तरह से हो सकते हैं:

public void orderMyPizza(IPizza myPizza) {
//This will always work, because everyone MUST implement order
      myPizza.order();
}

इस तरह से आप बहुरूपता का उपयोग कर रहे हैं और आप सभी का ख्याल है कि आपकी वस्तुएं ऑर्डर करने के लिए प्रतिक्रिया दें ()।


4

मैंने इस पृष्ठ पर "रचना" शब्द की खोज की और इसे एक बार भी नहीं देखा। यह उत्तर उपर्युक्त उत्तरों के अतिरिक्त बहुत अधिक है।

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

डेरेक बानस द्वारा यह शानदार "डेकोरेटर पैटर्न" ट्यूटोरियल (जो कि काफी मजेदार है - उदाहरण के तौर पर पिज्जा का भी उपयोग करता है) एक सार्थक चित्रण है:

https://www.youtube.com/watch?v=j40kRwSm4VE


2
मैं वास्तव में हैरान हूं कि यह सबसे अच्छा जवाब नहीं है। उनकी सभी उपयोगिता में इंटरफेस, रचना में सबसे बड़ा उपयोग है।
मैकीज सिटको

3

विभिन्न वर्गों के बीच संबंध लागू करने के लिए इंटरफेस हैं। उदाहरण के लिए, आपके पास कार और पेड़ के लिए एक वर्ग है;

public class Car { ... }

public class Tree { ... }

आप दोनों वर्गों के लिए एक ज्वलनशील कार्यक्षमता जोड़ना चाहते हैं। लेकिन प्रत्येक वर्ग के पास जलाने के अपने तरीके हैं। तो आप बस बनाते हैं;

public class Car : IBurnable
{
public void Burn() { ... }
}

public class Tree : IBurnable
{
public void Burn() { ... }
}

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

1
इस बात से सहमत। इंटरफ़ेस = "कर सकते हैं"। क्लास / एब्सट्रैक्ट केल्स = "इज़ ए"
पीटर.वांग ३०'१६ को s:

3

आपको इंटरफेस मिलेगा, जब आपको उनकी आवश्यकता होगी :) आप उदाहरणों का अध्ययन कर सकते हैं, लेकिन आपको अहा की आवश्यकता है! प्रभाव वास्तव में उन्हें पाने के लिए।

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


3

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

आइए एक पूर्ण स्वाद 3 कोर्स भोजन कहने के लिए पिज्जा सादृश्य का विस्तार करें। हमारे पास अभी भी Prepare()हमारे सभी खाद्य श्रेणियों के लिए मुख्य इंटरफ़ेस होगा, लेकिन हमारे पास निश्चित रूप से चयन (स्टार्टर, मुख्य, मिठाई) के लिए सार घोषणाएं भी होंगी, और भोजन के प्रकार (दिलकश / मीठे, शाकाहारी / मांसाहारी) के लिए अलग-अलग गुण होंगे। लस मुक्त आदि)।

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

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


1
यह उत्तर अधिक अंक का हकदार है! डिज़ाइन किए गए पैटर्नों में उपयोग किए जाने पर इंटरफ़ेस चमकता है जैसे कि स्टेट पैटर्न। अतिरिक्त जानकारी के लिए plus.google.com/+ZoranHorvat-Programming देखें
एलेक्स नोलास्को

3

यहां उन वस्तुओं के लिए एक इंटरफ़ेस है, जिनके पास एक आयताकार आकार है:

interface IRectangular
{
    Int32 Width();
    Int32 Height();
}

यह सब मांग करता है कि आप ऑब्जेक्ट की चौड़ाई और ऊंचाई तक पहुंचने के तरीकों को लागू करते हैं।

अब एक विधि को परिभाषित करते हैं जो किसी भी वस्तु पर काम करेगी जो है IRectangular:

static class Utils
{
    public static Int32 Area(IRectangular rect)
    {
        return rect.Width() * rect.Height();
    }
}

वह किसी भी आयताकार वस्तु का क्षेत्र लौटाएगा।

आइए एक वर्ग को लागू करें जो SwimmingPoolआयताकार है:

class SwimmingPool : IRectangular
{
    int width;
    int height;

    public SwimmingPool(int w, int h)
    { width = w; height = h; }

    public int Width() { return width; }
    public int Height() { return height; }
}

और एक अन्य वर्ग Houseजो आयताकार भी है:

class House : IRectangular
{
    int width;
    int height;

    public House(int w, int h)
    { width = w; height = h; }

    public int Width() { return width; }
    public int Height() { return height; }
}

यह देखते हुए कि, आप इस Areaविधि को घरों या स्विमिंग-पूलों पर कह सकते हैं:

var house = new House(2, 3);

var pool = new SwimmingPool(3, 4);

Console.WriteLine(Utils.Area(house));
Console.WriteLine(Utils.Area(pool));

इस तरह, आपकी कक्षाएं किसी भी संख्या के इंटरफेस से "विरासत" व्यवहार (स्थिर-तरीके) कर सकती हैं।


3

एक इंटरफ़ेस एक निश्चित कार्यक्षमता के प्रदाता और पत्राचार उपभोक्ताओं के बीच एक अनुबंध को परिभाषित करता है। यह अनुबंध (इंटरफ़ेस) से कार्यान्वयन को डिकूप करता है। आपको ऑब्जेक्ट ओरिएंटेड आर्किटेक्चर और डिज़ाइन पर एक नज़र डालनी चाहिए। आप विकिपीडिया से शुरू करना चाहते हैं: http://en.wikipedia.org/wiki/Interface_(computing)


3

क्या ?

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

में C#इंटरफेस प्रथा के अनुसार नाम लगाकर एक 'मैं' इसलिए यदि आप एक इंटरफेस आकार कहा जाता है करना चाहते हैं, तो आप इसे के रूप में घोषणा करेंगे द्वारा परिभाषित किया गया हैIShapes

अब क्यों ?

Improves code re-usability

मान लीजिए कि आप आकर्षित करना चाहते हैं Circle, Triangle. आप समूह कर सकते हैं उन्हें एक साथ और उन्हें फोन Shapesऔर तरीकों आकर्षित करने के लिए है Circleऔर Triangle लेकिन एक बुरा विचार ठोस कार्यान्वयन होने होगा क्योंकि कल आप अधिक 2 के लिए तय कर सकते हैं Shapes Rectangleऔर Square। अब जब आप उन्हें जोड़ते हैं तो एक बढ़िया मौका है कि आप अपने कोड के अन्य हिस्सों को तोड़ सकते हैं।

इंटरफ़ेस के साथ आप अनुबंध से अलग कार्यान्वयन को अलग करते हैं


लाइव परिदृश्य 1 दिन

आपको सर्कल और ट्राइएंगल ड्रा करने के लिए एक ऐप बनाने के लिए कहा गया था

interface IShapes
{
   void DrawShape();
   
 }

class Circle : IShapes
{
    
    public void DrawShape()
    {
        Console.WriteLine("Implementation to Draw a Circle");
    }
}

Class Triangle: IShapes
{
     public void DrawShape()
    {
        Console.WriteLine("Implementation to draw a Triangle");
    }
}
static void Main()
{
     List <IShapes> shapes = new List<IShapes>();
        shapes.Add(new Circle());
        shapes.Add(new Triangle());

        foreach(var shape in shapes)
        {
            shape.DrawShape();
        }
}

लाइव परिदृश्य 2 दिवस

यदि आपको ऐड Squareऔर इसके Rectangleलिए कहा गया है, तो आपको बस इतना करना है कि इसके लिए class Square: IShapesऔर Mainऐड इन लिस्ट में निहितार्थ पैदा करेंshapes.Add(new Square());


आप 6 साल पुराने सवाल के जवाब को क्यों जोड़ रहे हैं, दर्जनों अन्य उत्तर सैकड़ों बार सामने आए हैं? यहाँ कुछ भी नहीं है जो पहले से ही नहीं कहा गया है।
जोनाथन रेइनहार्ट

@JonathonReinhart, हाँ, मैंने ऐसा सोचा था, लेकिन तब मैं इस उदाहरण पर विचार कर रहा था और जिस तरह से इसके बारे में बताया गया है, वह शरीर को दूसरों से बेहतर बनाने में मदद करेगा।
क्लिंट

2

यहाँ बहुत सारे अच्छे उत्तर हैं, लेकिन मैं थोड़ा अलग दृष्टिकोण से कोशिश करना चाहूंगा।

आप वस्तु उन्मुख डिजाइन के ठोस सिद्धांतों से परिचित हो सकते हैं। संक्षेप में:

एस - सिंगल रिस्पॉन्सिबिलिटी प्रिंसिपल ओ - ओपन / क्लोज्ड प्रिंसिपल एल - लिस्कोव सबस्टीट्यूशन प्रिंसिपल I - इंटरफेस सेग्रिगेशन प्रिंसिपल D - डिपेंडेंसी इनवर्जन प्रिंसिपल

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

"हर पैमाने पर निर्भरता प्रबंधन सॉफ्टवेयर में महत्वपूर्ण चुनौती है" (डोनाल्ड नथ)

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

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


1

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


1

थेरेसी वास्तव में महान उदाहरण हैं।

एक और, एक स्विच स्टेटमेंट के मामले में, आपको हर बार जब आप चाहते हैं कि रीओ एक विशिष्ट तरीके से कार्य करना चाहते हैं, तो आपको बनाए रखने और स्विच करने की आवश्यकता नहीं है।

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

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

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


1

इंटरफेस के बारे में सोचने का सबसे सरल तरीका यह है कि विरासत का मतलब क्या है। यदि क्लास CC को क्लास C विरासत में मिली है, तो इसका मतलब है कि दोनों:

  1. क्लास सीसी कक्षा सी के किसी भी सार्वजनिक या संरक्षित सदस्यों का उपयोग कर सकते हैं जैसे कि वे अपने स्वयं के थे, और इस प्रकार केवल उन चीजों को लागू करने की आवश्यकता है जो मूल वर्ग में मौजूद नहीं हैं।
  2. एक सी के लिए एक संदर्भ को पारित किया जा सकता है या एक नियमित या चर को सौंपा जा सकता है जो एक सी के संदर्भ की अपेक्षा करता है।

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

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

इसकी एक अच्छी विशेषता (.net फ्रेमवर्क, IMHO में रेखांकित) है कि वे यह घोषित करना संभव बनाते हैं कि वस्तु जो कर सकती है, वह घोषणात्मक रूप से इंगित करती है। उदाहरण के लिए, कुछ ऑब्जेक्ट डेटा-सोर्स ऑब्जेक्ट चाहते हैं, जिससे वे इंडेक्स द्वारा चीजों को पुनः प्राप्त कर सकें (जैसा कि एक सूची के साथ संभव है), लेकिन उन्हें वहां कुछ भी स्टोर करने की आवश्यकता नहीं होगी। अन्य रूटीनों को एक डेटा-डिपॉजिटरी ऑब्जेक्ट की आवश्यकता होगी जहां वे चीजों को इंडेक्स द्वारा नहीं संग्रहित कर सकते हैं (जैसा कि Collection.Add के साथ), लेकिन उन्हें कुछ भी वापस पढ़ने की आवश्यकता नहीं होगी। कुछ डेटा प्रकार इंडेक्स द्वारा एक्सेस की अनुमति देंगे, लेकिन लिखने की अनुमति नहीं देंगे; अन्य लोग लेखन की अनुमति देंगे, लेकिन अनुक्रमणिका तक पहुंच की अनुमति नहीं देंगे। कुछ, निश्चित रूप से, दोनों की अनुमति देगा।

यदि ReadableByIndex और Appendable असंबंधित आधार वर्ग थे, तो एक प्रकार को परिभाषित करना असंभव होगा, जो ReadableByIndex और अपेक्षानुरूप अपेक्षा करने वाली चीजों दोनों को पारित किया जा सकता है। एक दूसरे से ReadableByIndex या Appendable व्युत्पन्न होने से इसे कम करने की कोशिश कर सकता है; व्युत्पन्न वर्ग को दोनों उद्देश्यों के लिए सार्वजनिक सदस्यों को उपलब्ध कराना होगा, लेकिन चेतावनी दी कि कुछ सार्वजनिक सदस्य वास्तव में काम नहीं कर सकते हैं। माइक्रोसॉफ्ट के कुछ वर्ग और इंटरफेस ऐसा करते हैं, लेकिन यह icky है। एक क्लीनर दृष्टिकोण विभिन्न प्रयोजनों के लिए इंटरफेस है, और फिर वस्तुओं को उन चीजों के लिए इंटरफेस को लागू करना है जो वे वास्तव में कर सकते हैं। यदि एक इंटरफ़ेस IReadableByIndex और दूसरा इंटरफ़ेस IAppendable था,


1

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

ओ = "कक्षाएं विस्तार के लिए खुली होनी चाहिए लेकिन संशोधन के लिए बंद कर दी जानी चाहिए"


1

मेरे लिए एक इंटरफ़ेस का लाभ / लाभ यह है कि यह एक अमूर्त वर्ग की तुलना में अधिक लचीला है। चूँकि आप केवल 1 सार वर्ग प्राप्त कर सकते हैं, लेकिन आप कई स्थानों को लागू कर सकते हैं, एक प्रणाली में परिवर्तन जो कई स्थानों पर एक सार वर्ग विरासत में मिला है समस्याग्रस्त हो जाता है। यदि इसे 100 स्थानों पर विरासत में मिला है, तो एक बदलाव के लिए सभी 100 में परिवर्तन की आवश्यकता होती है। लेकिन, इंटरफ़ेस के साथ, आप नए परिवर्तन को एक नए इंटरफ़ेस में रख सकते हैं और बस उस इंटरफ़ेस का उपयोग कर सकते हैं जहां इसकी आवश्यकता है (इंटरफ़ेस Seq। SOLID से)। इसके अतिरिक्त, मेमोरी उपयोग ऐसा लगता है कि यह इंटरफ़ेस के साथ कम होगा क्योंकि इंटरफ़ेस उदाहरण में एक ऑब्जेक्ट का उपयोग केवल एक बार मेमोरी में किया जाता है, इसके बावजूद कि इंटरफ़ेस कितनी जगहों पर लागू होता है।


1

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

मैं नीचे दिए गए ग्राफिक द्वारा समर्थित एक उदाहरण दूंगा।

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

यहां छवि विवरण दर्ज करें

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

public interface IMachine
{
    bool Start();
    bool Stop();
}

public class Car : IMachine
{
    public bool Start()
    {
        Console.WriteLine("Car started");
        return true;
    }

    public bool Stop()
    {
        Console.WriteLine("Car stopped");
        return false;
    }
}

public class Tank : IMachine
{
    public bool Start()
    {
        Console.WriteLine("Tank started");
        return true;
    }

    public bool Stop()
    {
        Console.WriteLine("Tank stopped");
        return false;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var car = new Car();
        car.Start();
        car.Stop();

        var tank = new Tank();
        tank.Start();
        tank.Stop();

    }
}

1
class Program {
    static void Main(string[] args) {
        IMachine machine = new Machine();
        machine.Run();
        Console.ReadKey();
    }

}

class Machine : IMachine {
    private void Run() {
        Console.WriteLine("Running...");
    }
    void IMachine.Run() => Run();
}

interface IMachine
{
    void Run();
}

इसका वर्णन एक अलग दृष्टिकोण से करता हूँ। आइए उदाहरण के अनुसार एक कहानी बनाएं जो मैंने ऊपर दिखाया है;

कार्यक्रम, मशीन और IMachine हमारी कहानी के अभिनेता हैं। प्रोग्राम चलाना चाहता है लेकिन उसमें वह क्षमता नहीं है और मशीन को पता है कि उसे कैसे चलाना है। मशीन और IMachine सबसे अच्छे दोस्त हैं, लेकिन प्रोग्राम मशीन के साथ बोलने की शर्तों पर नहीं है। इसलिए प्रोग्राम और IMachine ने एक सौदा किया और निर्णय लिया कि IMachine प्रोग्राम को बताएगा कि लुकिंग मशीन (एक परावर्तक की तरह) कैसे चले।

और प्रोग्राम IMachine की मदद से चलाना सीखता है।

इंटरफ़ेस संचार और विकासशील युग्मित परियोजनाओं को प्रदान करता है।

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


1

मुझे पता है कि मुझे बहुत देर हो चुकी है .. (लगभग नौ साल), लेकिन अगर कोई छोटा स्पष्टीकरण चाहता है तो आप इसके लिए जा सकते हैं:

सरल शब्दों में, आप इंटरफ़ेस का उपयोग तब करते हैं जब आपको पता होता है कि कोई ऑब्जेक्ट क्या कर सकता है या किसी ऑब्जेक्ट पर हम क्या कार्य करने जा रहे हैं .. उदाहरण इन्सर्ट, अपडेट और डिलीट।

interface ICRUD{
      void InsertData(); // will insert data
      void UpdateData(); // will update data
      void DeleteData(); // will delete data
}

महत्वपूर्ण नोट: इंटरफेस हमेशा सार्वजनिक होते हैं।

उम्मीद है की यह मदद करेगा।

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