इसका क्या मतलब है "एक इंटरफ़ेस के लिए कार्यक्रम"?


813

मैंने इसका उल्लेख कई बार देखा है और इसका मतलब क्या है, इस पर मैं स्पष्ट नहीं हूं। आप ऐसा कब और क्यों करेंगे?

मुझे पता है कि इंटरफेस क्या करते हैं, लेकिन मैं इस पर स्पष्ट नहीं हूं, मुझे लगता है कि मैं उन्हें सही तरीके से उपयोग करने से चूक रहा हूं।

यदि आप ऐसा करने के लिए थे तो क्या ऐसा है:

IInterface classRef = new ObjectWhatever()

आप किसी भी वर्ग का उपयोग कर सकते हैं जो लागू करता है IInterface? आपको ऐसा कब करना होगा? केवल एक चीज मैं सोच सकता हूं कि क्या आपके पास एक तरीका है और आप इस बात के बारे में अनिश्चित हैं कि इसे लागू करने के अलावा किस वस्तु को पारित किया जाएगा IInterface। मैं नहीं सोच सकता कि आपको कितनी बार ऐसा करने की आवश्यकता होगी।

इसके अलावा, आप एक ऐसी विधि कैसे लिख सकते हैं जो एक वस्तु में होती है जो एक इंटरफ़ेस को लागू करती है? क्या यह संभव है?


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

18
@ और टर्नर: यह खराब सलाह है। 1)। "आपके कार्यक्रम को इष्टतम होने की आवश्यकता है" इंटरफेस को स्वैप करने का एक अच्छा कारण नहीं है! फिर आप कहते हैं कि "अपने कोड को इंटरफेस में क्रमादेशित करें, हालांकि ..." तो आप सलाह दे रहे हैं कि आवश्यकता (1) तब आप उप-इष्टतम कोड जारी करें?
मिच गेहूं

74
यहां अधिकांश उत्तर बिल्कुल सही नहीं हैं। इसका मतलब यह नहीं है या यहां तक ​​कि "इंटरफ़ेस कीवर्ड का उपयोग करें" बिल्कुल भी नहीं है। एक इंटरफ़ेस कुछ का उपयोग करने का एक तरीका है - अनुबंध का पर्यायवाची (इसे देखें)। इससे अलग होना कार्यान्वयन है, जो कि अनुबंध कैसे पूरा होता है। केवल विधि / प्रकार की गारंटी के खिलाफ कार्यक्रम ताकि, जब विधि / प्रकार को उस तरीके से बदल दिया जाए जो अभी भी अनुबंध का पालन करता है, तो यह कोड का उपयोग करके इसे नहीं तोड़ता है।
ज्ञानदेव

2
@ apollodude217 जो वास्तव में पूरे पृष्ठ पर सबसे अच्छा उत्तर है। शीर्षक में प्रश्न के लिए कम से कम, क्योंकि यहां कम से कम 3 काफी अलग प्रश्न हैं ...
एंड्रयू स्पेंसर

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

जवाबों:


1633

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

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

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

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

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

मान लीजिए कि हमारे खेल को किसी प्रकार की यादृच्छिक चीज़ की आवश्यकता होती है, जो खेल खिलाड़ी को रात्रिभोज खाने पर परेशान करती है। यह एक HouseFlyया एक Telemarketerया दोनों हो सकता है - लेकिन आप दोनों को एक ही फ़ंक्शन के लिए कैसे अनुमति देते हैं? और आप प्रत्येक भिन्न प्रकार की वस्तु को उसी तरह से "उनकी कष्टप्रद बात" कैसे करते हैं?

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

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

अब हमारे पास दो कक्षाएं हैं जो प्रत्येक अपने तरीके से कष्टप्रद हो सकती हैं। और उन्हें एक ही आधार वर्ग से प्राप्त करने और सामान्य निहित विशेषताओं को साझा करने की आवश्यकता नहीं है - उन्हें बस अनुबंध को संतुष्ट करने की आवश्यकता है IPest- यह अनुबंध सरल है। आपको बस करना है BeAnnoying। इस संबंध में, हम निम्नलिखित मॉडल कर सकते हैं:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

यहां हमारे पास एक डाइनिंग रूम है जो कई डिनर और कई कीटों को स्वीकार करता है - इंटरफ़ेस के उपयोग पर ध्यान दें। इसका मतलब यह है कि हमारी छोटी दुनिया में, pestsसरणी का एक सदस्य वास्तव में एक Telemarketerवस्तु या वस्तु हो सकता है HouseFly

ServeDinnerजब रात का खाना परोसा जाता है और खाने के कमरे में हमारे लोगों को खाने के लिए अपेक्षा की जाती है विधि कहा जाता है। हमारे छोटे खेल में, जब हमारे कीट अपना काम करते हैं - प्रत्येक कीट को IPestइंटरफ़ेस के माध्यम से परेशान करने का निर्देश दिया जाता है। इस तरह, हम आसानी से दोनों को प्राप्त कर सकते हैं Telemarketersऔर HouseFlysअपने प्रत्येक तरीके से परेशान हो सकते हैं - हम केवल इस बात की परवाह करते हैं कि हमारे पास उस DiningRoomवस्तु में कुछ है जो एक कीट है, हम वास्तव में परवाह नहीं करते हैं कि यह क्या है और उनमें कुछ भी नहीं हो सकता है अन्य के साथ आम है।

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


3
एक और बात पर विचार करना है कि कुछ मामलों में यह उन चीजों के लिए एक इंटरफ़ेस के लिए उपयोगी हो सकता है जो "कष्टप्रद" हो सकते हैं, और वस्तुओं की एक भिन्नता BeAnnoyingको एक नो-ऑप के रूप में लागू करते हैं; इस इंटरफेस के स्थान पर मौजूद हो सकता है, या करने के लिए, चीजें हैं जो कष्टप्रद हैं के लिए इंटरफ़ेस अलावा (यदि दोनों इंटरफेस मौजूद हैं, "चीजें हैं जो कर रहे हैं कष्टप्रद" इंटरफेस "चीजें हैं जो से विरासत चाहिए हो सकता है कष्टप्रद" इंटरफेस)। ऐसे इंटरफेस का उपयोग करने का नुकसान यह है कि स्टब विधियों की "कष्टप्रद" संख्या को लागू करने के साथ कार्यान्वयन पर बोझ पड़ सकता है। फायदा यह है कि ...
सुपर जट

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

33
एनकैप्सुलेटिंग व्यवहार, जैसे कि IPest को रणनीति पैटर्न के रूप में जाना जाता है, जब किसी को उस विषय पर अधिक सामग्री के साथ पालन करने में रुचि होती है ...
nckbrz

9
दिलचस्प बात यह है कि आप इस ओर इशारा नहीं करते हैं क्योंकि ऑब्जेक्ट IPest[]IPest संदर्भ में हैं, आप कॉल कर सकते हैं BeAnnoying()क्योंकि उनके पास वह विधि है, जबकि आप अन्य विधियों को बिना कास्ट के नहीं कह सकते। हालांकि, प्रत्येक ऑब्जेक्ट को व्यक्तिगत BeAnnoying()विधि कहा जाएगा।
डी। बेन नोबल

4
बहुत अच्छी व्याख्या ... मुझे बस यहाँ यह कहने की ज़रूरत है: मैंने कभी भी इंटरफेस को किसी तरह के ढीले वंशानुक्रम तंत्र के बारे में नहीं सुना है, लेकिन इसके बजाय मुझे विरासत के बारे में पता है कि इंटरफेस को परिभाषित करने के लिए एक खराब तंत्र के रूप में इस्तेमाल किया जा रहा है (उदाहरण के लिए, नियमित रूप से पायथन में यह हर समय करना)।
कार्लोस एच रोमानो

282

छात्रों को मैं जो विशिष्ट उदाहरण देता था, वह यह है कि उन्हें लिखना चाहिए

List myList = new ArrayList(); // programming to the List interface

के बजाय

ArrayList myList = new ArrayList(); // this is bad

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

List myList = new TreeList();

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

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

public ArrayList doSomething(HashMap map);

यह विधि घोषणा आपको दो ठोस कार्यान्वयन ( ArrayListऔर HashMap) से जोड़ती है । जैसे ही उस पद्धति को अन्य कोड से कॉल किया जाता है, उन प्रकारों में कोई भी बदलाव का मतलब है कि आपको कॉलिंग कोड को भी बदलना होगा। बेहतर होगा कि इंटरफेस को प्रोग्राम करें।

public List doSomething(Map map);

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


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
यवेटे

बहुत स्पष्ट व्याख्या। बहुत मददगार
samuel luswata

मेरे पास आपके द्वारा बताए गए कारण पर एक प्रश्न है "पहली घोषणा यह सुनिश्चित करती है कि आप केवल myList पर कॉल विधियों को सूचीबद्ध करें जो सूची इंटरफ़ेस (इसलिए कोई ArrayList विशिष्ट विधियाँ) द्वारा परिभाषित नहीं हैं। यदि आपने इस तरह से इंटरफ़ेस के लिए प्रोग्राम किया है, तो बाद में आप पर। यह तय कर सकते हैं कि आपको वास्तव में सूची myList = new TreeList () की आवश्यकता है, और आपको केवल एक ही बार में अपना कोड बदलना होगा। " शायद मुझे गलतफहमी हो गई है, मुझे आश्चर्य है कि अगर आपको "यह सुनिश्चित करना है कि आप केवल मायलिस्ट पर कॉल करने के तरीके" चाहते हैं तो आपको ArrayList को TreeList में बदलने की आवश्यकता क्यों है?
user3014901

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

73

एक इंटरफ़ेस को प्रोग्रामिंग कह रहा है, "मुझे इस कार्यक्षमता की आवश्यकता है और मुझे परवाह नहीं है कि यह कहाँ से आता है।"

(जावा में), Listइंटरफ़ेस बनाम ArrayListऔर LinkedListठोस वर्गों पर विचार करें। अगर मुझे परवाह है कि मेरे पास एक डेटा संरचना है जिसमें कई डेटा आइटम हैं जिन्हें मुझे पुनरावृत्ति के माध्यम से एक्सेस करना चाहिए, तो मैं एक List(और वह समय का 99%) चुनूंगा। अगर मुझे पता है कि मुझे सूची के किसी भी छोर से निरंतर-समय डालने / हटाने की आवश्यकता है, तो मैं LinkedListकंक्रीट कार्यान्वयन (या अधिक संभावना, क्यू इंटरफ़ेस का उपयोग कर सकता हूं) चुन सकता हूं । अगर मुझे पता है कि मुझे इंडेक्स द्वारा रैंडम एक्सेस की आवश्यकता है, तो मैं ArrayListकंक्रीट क्लास चुनूंगा।


1
पूरी तरह से सहमत अर्थात जो किया जाता है, उसके बीच की स्वतंत्रता कैसे होती है। स्वतंत्र घटकों के साथ एक प्रणाली को विभाजित करके, आप एक ऐसी प्रणाली के साथ समाप्त होते हैं जो सरल और पुन: प्रयोज्य है (
क्लूजुर बनाने वाले

38

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

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

EDIT: नीचे एक लेख का लिंक दिया गया है, जहां Erich Gamma ने अपने उद्धरण, "एक इंटरफ़ेस के लिए कार्यक्रम, एक कार्यान्वयन नहीं" पर चर्चा की।

http://www.artima.com/lejava/articles/designprinciples.html


3
कृपया, इस साक्षात्कार को फिर से पढ़ें: गामा बेशक इंटरफ़ेस की OO अवधारणा के बारे में बात कर रहे थे, न कि JAVA या C # विशेष प्रकार की कक्षा (ISomething) के बारे में। समस्या यह है कि ज्यादातर लोग, हालांकि वह कीवर्ड के बारे में बात कर रहे थे, इसलिए अब हमारे पास बहुत सारे अनएडेड इंटरफेस (ISomething) हैं।
सिल्वेन

बहुत अच्छा साक्षात्कार। कृपया, भविष्य के पाठकों के लिए सावधान रहें, साक्षात्कार में चार पृष्ठ हैं। मैं इसे देखने से पहले ब्राउज़र को लगभग बंद कर दूंगा।
विज्ञापन Infinitum

37

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

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

संपादित करें: और डेटाबेस के साथ इसका मतलब है कि प्रत्यक्ष तालिका पहुंच के बजाय विचारों और संग्रहीत प्रक्रियाओं का उपयोग करना।


5
सबसे बढ़िया उत्तर। गामा यहाँ एक समान विवरण देते हैं: artima.com/lejava/articles/designprinciples.html (पृष्ठ 2 देखें)। वह OO अवधारणा का उल्लेख कर रहा है, लेकिन आप सही हैं: यह तब बड़ा होता है।
सिल्वेन रोड्रिग

36

आपको नियंत्रण के व्युत्क्रम में देखना चाहिए:

ऐसे परिदृश्य में, आप इसे नहीं लिखेंगे:

IInterface classRef = new ObjectWhatever();

आप कुछ इस तरह लिखेंगे:

IInterface classRef = container.Resolve<IInterface>();

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

यदि हम तालिका से IoC छोड़ते हैं, तो आप कोड लिख सकते हैं जो जानता है कि यह किसी ऐसी वस्तु से बात कर सकता है जो कुछ विशिष्ट करता है , लेकिन यह नहीं कि किस प्रकार की वस्तु या यह कैसे करता है।

पैरामीटर पास करते समय यह काम आएगा।

आपके लघु प्रश्न के अनुसार "इसके अलावा, आप एक ऐसी विधि कैसे लिख सकते हैं जो एक ऑब्जेक्ट में ले जाती है जो एक इंटरफ़ेस को लागू करता है। क्या यह संभव है?", C # में आप बस पैरामीटर प्रकार के लिए इंटरफ़ेस प्रकार का उपयोग करेंगे, जैसे:

public void DoSomethingToAnObject(IInterface whatever) { ... }

यह सही में "किसी वस्तु से बात करता है जो कुछ विशिष्ट करता है।" ऊपर बताई गई विधि यह जानती है कि वस्तु से क्या अपेक्षा की जाए, कि यह IInterface में सब कुछ लागू करती है, लेकिन यह परवाह नहीं करती है कि यह किस प्रकार की वस्तु है, केवल यह अनुबंध का पालन करती है, जो कि एक इंटरफ़ेस है।

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

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

मैं आपको एक ठोस उदाहरण देता हूं।

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

अब चूंकि नियंत्रण पूर्व-परिभाषित वर्गों से विरासत में मिला है, जिन पर हमारा कोई नियंत्रण नहीं है, हम तीन चीजों में से एक कर सकते हैं:

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

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


31
आईओसी का उल्लेख शुरुआत में ही क्यों किया गया क्योंकि इससे केवल भ्रम अधिक होगा।
केविन ले - खनेले

1
सहमत हूं, मैं कहूंगा कि इंटरफेस के खिलाफ प्रोग्रामिंग आईओसी को आसान और विश्वसनीय बनाने के लिए सिर्फ एक तकनीक है।
टेरजेटाइल

28

इंटरफ़ेस पर कोड लागू नहीं जावा के साथ क्या करना है, और न ही इसका इंटरफ़ेस निर्माण।

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

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

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

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

इस सोच को हिलाएं कि जावा इंटरफेस के पास to प्रोग्राम टू द इंटरफेस, नॉट इंप्लीमेंटेशन ’की अवधारणा के साथ क्या-क्या करना है। वे अवधारणा को लागू करने में मदद कर सकते हैं, लेकिन वे अवधारणा नहीं हैं ।


1
पहला वाक्य यह सब कहता है। यह स्वीकृत उत्तर होना चाहिए।
मदुमला

14

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

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

तब मैं GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, आदि बना सकता था।

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

फिर JpegImageLoader, GifImageLoader, PngImageLoader, आदि बनाएँ।

अधिकांश ऐड-इन्स और प्लगइन सिस्टम इंटरफेस को काम करते हैं।

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

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

तब मैं एक XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, आदि बना सकता था। अपने वेब अनुप्रयोगों के लिए, मैं अक्सर XML रिपॉजिटरी का निर्माण जल्दी करता हूं ताकि मैं SQL डेटाबेस तैयार होने से पहले कुछ प्राप्त कर सकूं और चल सके। डेटाबेस तैयार होने के बाद मैं XML संस्करण को बदलने के लिए SQLRepository लिखता हूं। मेरे बाकी कोड अपरिवर्तित बने हुए हैं क्योंकि यह पूरी तरह से इंटरफेस से चलता है।

तरीके इंटरफेस को स्वीकार कर सकते हैं जैसे:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

10

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

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

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

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


9

वहाँ बहुत सारे स्पष्टीकरण, लेकिन इसे और भी सरल बनाने के लिए। उदाहरण के लिए ए List। एक के रूप में एक सूची के साथ लागू कर सकते हैं:

  1. एक आंतरिक सरणी
  2. एक लिंक की गई सूची
  3. अन्य कार्यान्वयन

एक इंटरफेस के निर्माण से, एक कहते हैं List। आप केवल सूची की परिभाषा या Listवास्तविकता में क्या मतलब है के रूप में कोड ।

आप किसी भी प्रकार के कार्यान्वयन को आंतरिक रूप से कार्यान्वयन कह सकते हैं array। लेकिन मान लीजिए कि आप बग या प्रदर्शन के कारण किसी कारण से कार्यान्वयन को बदलना चाहते हैं। फिर आपको बस घोषणा List<String> ls = new ArrayList<String>()को बदलना होगा List<String> ls = new LinkedList<String>()

कहीं और कोड में, क्या आपको कुछ और बदलना होगा; क्योंकि बाकी सब की परिभाषा पर बनाया गया था List


8

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


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

3
JDBC इतना खराब है कि इसे बदलने की जरूरत है। एक और उदाहरण खोजें।
जोशुआ

JDBC खराब है, लेकिन इंटरफ़ेस बनाम कार्यान्वयन या अमूर्त के स्तरों के साथ किसी भी कारण से नहीं। और इसलिए प्रश्न में अवधारणा को स्पष्ट करने के लिए, यह एकदम सही है।
एरविन स्मॉर्ट

8

Interfaces का प्रोग्रामिंग बहुत बढ़िया है, यह ढीली कपलिंग को बढ़ावा देता है। जैसा कि @lassevk ने उल्लेख किया है, व्युत्क्रम नियंत्रण इसका एक बड़ा उपयोग है।

इसके अलावा, ठोस प्राचार्यों में देखेंयहाँ एक वीडियो श्रृंखला है

यह एक कठिन कोडित (दृढ़ता से युग्मित उदाहरण) से गुजरता है, फिर इंटरफेस को देखता है, अंत में एक IoC / DI टूल (NInject) में प्रगति करता है


7

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

यह कहा गया है, पी पर। 18:

एक अंतरफलक के लिए कार्यक्रम, एक कार्यान्वयन नहीं

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

और इसके बाद, यह इसके साथ शुरू हुआ:

सार वर्गों द्वारा परिभाषित इंटरफेस के संदर्भ में केवल वस्तुओं में हेरफेर करने के दो लाभ हैं:

  1. ग्राहक उन विशिष्ट प्रकार की वस्तुओं से अनजान रहते हैं, जिनका वे उपयोग करते हैं, जब तक कि ग्राहक उस इंटरफ़ेस का पालन नहीं करते हैं, जिसकी ग्राहक अपेक्षा करते हैं।
  2. ग्राहक इन वस्तुओं को लागू करने वाले वर्गों से अनजान रहते हैं। ग्राहक केवल इंटरफ़ेस को परिभाषित करने वाले अमूर्त वर्ग (तों) के बारे में जानते हैं।

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


6

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


5

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


4

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


4

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

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

  1. हमें प्रासंगिक रूप से अनुचित काम करने से रोकता है, और
  2. हमें भविष्य में कार्यान्वयन को सुरक्षित रूप से बदलने देता है।

उदाहरण के लिए, Personउस वर्ग पर विचार करें जो Friendऔर Employeeइंटरफ़ेस को लागू करता है।

class Person implements AbstractEmployee, AbstractFriend {
}

व्यक्ति के जन्मदिन के संदर्भ में, हम Friendइंटरफ़ेस को प्रोग्राम करते हैं , ताकि व्यक्ति की तरह व्यवहार न किया जा सके Employee

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

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

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

महान। हमने अलग-अलग संदर्भों में उचित व्यवहार किया है, और हमारा सॉफ्टवेयर अच्छी तरह से काम कर रहा है।

भविष्य में, यदि हमारा व्यवसाय कुत्तों के साथ काम करने के लिए बदलता है, तो हम सॉफ्टवेयर को काफी आसानी से बदल सकते हैं। सबसे पहले, हम एक Dogवर्ग बनाते हैं जो दोनों को लागू करता है Friendऔर Employee। फिर, हम सुरक्षित रूप से बदल new Person()जाते हैं new Dog()। यहां तक ​​कि अगर दोनों फ़ंक्शन में हजारों लाइनें हैं, तो यह सरल संपादन काम करेगा क्योंकि हम जानते हैं कि निम्नलिखित सत्य हैं:

  1. फ़ंक्शन partyकेवल Friendसबसेट का उपयोग करता है Person
  2. फ़ंक्शन workplaceकेवल Employeeसबसेट का उपयोग करता है Person
  3. वर्ग Dogदोनों को लागू करता है Friendऔर Employeeइंटरफेस।

दूसरी ओर, यदि या तो partyया workplaceथे के खिलाफ प्रोग्राम किया है करने के लिए Person, वहाँ दोनों के होने का खतरा हो सकता है Personविशिष्ट कोड। से बदलने के Personलिए Dogहमें कोड के माध्यम से कंघी करने की आवश्यकता होगी किसी भी Personविशिष्ट कोड है कि Dogसमर्थन नहीं करता है।

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


1
यह मानते हुए कि आपके पास अत्यधिक व्यापक इंटरफेस नहीं है, अर्थात।
केसी

4

अगर मैं Swimmerकार्यक्षमता जोड़ने के लिए एक नया वर्ग लिख रहा हूँ swim()और कक्षा के किसी ऑब्जेक्ट का उपयोग करने की आवश्यकता है Dog, और यह Dogवर्ग इंटरफ़ेस को लागू करता है Animalजो घोषित करता है swim()

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

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


3

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

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


3

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

यह किसी भी विशिष्ट प्लगइन वर्ग के लिए पूरी तरह से स्वतंत्र बनाता है - यह परवाह नहीं करता है कि कक्षाएं क्या हैं। यह केवल परवाह करता है कि वे इंटरफ़ेस विनिर्देश पूरा करें।

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

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


3

सी ++ स्पष्टीकरण।

एक इंटरफ़ेस के बारे में अपनी कक्षाओं के सार्वजनिक तरीकों के रूप में सोचें।

आप तब एक टेम्पलेट बना सकते हैं जो इन सार्वजनिक विधियों पर 'निर्भर करता है' ताकि यह अपना कार्य कर सके (यह कक्षाओं को सार्वजनिक इंटरफ़ेस में परिभाषित फ़ंक्शन कॉल करता है)। बता दें कि यह टेम्पलेट एक वेक्टर क्लास की तरह एक कंटेनर है, और यह जिस इंटरफ़ेस पर निर्भर करता है वह एक खोज एल्गोरिदम है।

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

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

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

यह समय बचाता है (OOP सिद्धांत 'कोड पुन: उपयोग') जैसा कि आप बार-बार के बजाय एक एल्गोरिथ्म लिखने में सक्षम होते हैं और फिर से एक अतिवृद्धि विरासत पेड़ के साथ समस्या को जटिल किए बिना हर नई वस्तु के लिए विशिष्ट बनाते हैं।

चीजें कैसे संचालित होती हैं, इसके बारे में 'लापता'; बिग-टाइम (कम से कम C ++ में), यही कारण है कि अधिकांश मानक TEMPLATE लाइब्रेरी का ढाँचा संचालित होता है।

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

यह एक बहुत बड़ा विषय है और डिजाइन पैटर्न के आधारशिला सिद्धांतों में से एक है।


3

जावा में ये ठोस कक्षाएं सभी चारसेंसेंस इंटरफ़ेस को लागू करती हैं:

चारबफ़र, स्ट्रिंग, स्ट्रिंगबफ़र, स्ट्रिंगबर्ल

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

फिर भी इन वर्गों में से प्रत्येक चारसालेंस इंटरफ़ेस विधियों को उपयुक्त रूप से लागू करने में सक्षम है:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

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

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

बफ़रड्राइवर, चारआयरराइटर, चारब्रैफ़र, फाइलविटर, फिल्टरवेटर, लॉगस्ट्र्रीम, आउटपुटस्ट्रीमव्यू, आउटपुटस्ट्रीमर, पिपेडवृटर, प्रिंटस्ट्रीम, प्रिंटविटर, स्ट्रीटरबफ़र, स्ट्रिंगब्यूरो, स्ट्रिंगराइटर, राइटर।


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

... संचालन की तरह indexOfजल्दी, वहाँ कोई रास्ता नहीं है कि एक फोन करने वाला जो किसी विशेष कार्यान्वयन से परिचित नहीं है, CharSequenceवह charAtप्रत्येक व्यक्तिगत चरित्र की जांच करने के लिए उपयोग करने के बजाय ऐसा करने के लिए कह सकता है ।
सुपरकैट

3

लघुकथा: एक डाकिया को घर जाने के लिए कहा जाता है और कवर प्राप्त करने के लिए उस पर लिखे पते के साथ कवर (पत्र, दस्तावेज, चेक, उपहार कार्ड, आवेदन, प्रेम पत्र) प्राप्त होते हैं।

मान लीजिए कि कोई कवर नहीं है और पोस्टमैन को घर जाने के लिए कहें और सभी चीजें प्राप्त करें और अन्य लोगों को वितरित करें, पोस्टमैन भ्रमित हो सकता है।

तो बेहतर है इसे कवर के साथ लपेटें (हमारी कहानी में यह इंटरफ़ेस है) तो वह अपना काम ठीक करेगा।

अब पोस्टमैन का काम केवल कवर प्राप्त करना और वितरित करना है (वह कवर में अंदर क्या है परेशान नहीं करेगा)।

का एक प्रकार बनाएँ interface वास्तविक प्रकार न , लेकिन इसे वास्तविक प्रकार के साथ लागू करें।

इंटरफ़ेस बनाने के लिए आपके घटकों का मतलब है कोड के बाकी हिस्सों में आसानी से फिट हो

मैं आपको एक उदाहरण देता हूं।

आपके पास नीचे जैसा AirPlane इंटरफ़ेस है।

interface Airplane{
    parkPlane();
    servicePlane();
}

मान लीजिए कि आपके पास योजना के अपने नियंत्रक वर्ग के तरीके हैं

parkPlane(Airplane plane)

तथा

servicePlane(Airplane plane)

आपके कार्यक्रम में लागू किया गया। यह आपके कोड को ब्रेक नहीं करेगा । मेरा मतलब है, जब तक यह तर्क स्वीकार नहीं करता है तब तक इसे बदलने की जरूरत नहीं हैAirPlane

क्योंकि यह वास्तविक प्रकार के बावजूद किसी भी हवाई जहाज को स्वीकार करेंगे, flyer, highflyr,fighter , आदि

इसके अलावा, एक संग्रह में:

List<Airplane> plane; // अपने सभी विमानों को ले जाएगा।

निम्नलिखित उदाहरण से आपकी समझ साफ हो जाएगी।


आपके पास एक लड़ाकू विमान है जो इसे लागू करता है, इसलिए

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

HighFlyer और अन्य clasess के लिए एक ही बात:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

अब AirPlaneकई बार अपने नियंत्रक वर्गों का उपयोग करके सोचें ,

मान लीजिए कि आपका नियंत्रक वर्ग नीचे की तरह ControlPlane है,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

यहां जादू आता है क्योंकि आप अपने नए AirPlaneप्रकार के उदाहरण बना सकते हैं जितना आप चाहते हैं और आप ControlPlaneकक्षा के कोड को नहीं बदल रहे हैं ।

आप एक उदाहरण जोड़ सकते हैं ...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

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


2

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

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


2

Q: - ... "क्या आप इंटरफ़ेस को लागू करने वाले किसी भी वर्ग का उपयोग कर सकते हैं?"
A: - हाँ।

Q: - ... "आपको ऐसा कब करना होगा?"
ए: - हर बार आपको एक वर्ग (तों) की आवश्यकता होती है जो इंटरफ़ेस को लागू करता है।

नोट: हम एक वर्ग द्वारा कार्यान्वित नहीं किए गए इंटरफ़ेस को सच कर सकते हैं - यह सच है।

  • क्यों?
  • क्योंकि इंटरफ़ेस में केवल विधि प्रोटोटाइप हैं, न कि परिभाषाएँ (बस फ़ंक्शंस के नाम, न कि उनके तर्क)

AnIntf anInst = new Aclass();
// हम ऐसा तभी कर सकते हैं जब अकलस अनइंतेफ को लागू करता है।
// एनास्ट में अकलस संदर्भ होगा।


नोट: अब हम समझ सकते हैं कि अगर Bclass और Cclass ने एक ही Dintf को लागू किया तो क्या हुआ।

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

हमारे पास क्या है: समान इंटरफ़ेस प्रोटोटाइप (इंटरफ़ेस में फ़ंक्शन नाम), और विभिन्न कार्यान्वयन कहते हैं।

ग्रंथ सूची: प्रोटोटाइप - विकिपीडिया


1

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

IInterface classRef = new ObjectWhatever()

आप IInterface को लागू करने वाले किसी भी वर्ग का उपयोग कर सकते हैं? आपको ऐसा कब करना होगा?

अच्छे उदाहरण के लिए इस एसई प्रश्न पर एक नज़र डालें।

जावा वर्ग के लिए इंटरफ़ेस क्यों पसंद किया जाना चाहिए?

इंटरफ़ेस हिट प्रदर्शन का उपयोग करता है?

यदि हां तो कितना?

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

कोड के दो बिट्स को बनाए रखने के बिना आप इसे कैसे बचा सकते हैं?

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

एक अच्छा उपयोग मामला: रणनीति पैटर्न का कार्यान्वयन:

रणनीति पैटर्न का वास्तविक विश्व उदाहरण


1

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

मुझे लगता है कि ये नियम मेरी मदद करते हैं:

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

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

ध्यान दें कि उन्हें कब उपयोग करना है, इस पर विचार करने के दो तरीके हैं। उम्मीद है की यह मदद करेगा।


0

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

इकाई का परीक्षण

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

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

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

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

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

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


0

आइए पहले कुछ परिभाषाओं के साथ शुरुआत करें:

इंटरफ़ेस एन। ऑब्जेक्ट के संचालन द्वारा परिभाषित सभी हस्ताक्षरों के सेट को ऑब्जेक्ट के लिए इंटरफ़ेस कहा जाता है

एन टाइप करें एक विशेष इंटरफ़ेस

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

एक प्रकार जो ऊपर परिभाषित किया गया है वह एक विशेष इंटरफ़ेस है। मैं प्रदर्शित करने के लिए बनाया-अप आकार इंटरफ़ेस का उपयोग करेगा: draw(), getArea(), getPerimeter()आदि ..

यदि कोई ऑब्जेक्ट डेटाबेस प्रकार का है, तो हमारा मतलब है कि यह डेटाबेस इंटरफेस query(), commit()आदि के संदेशों / अनुरोधों को स्वीकार करता है । ऑब्जेक्ट कई प्रकार के हो सकते हैं। आपके पास एक डेटाबेस ऑब्जेक्ट आकार प्रकार का हो सकता है जब तक कि वह अपने इंटरफ़ेस को लागू करता है, जिस स्थिति में यह उप-टाइपिंग होगा

कई ऑब्जेक्ट कई अलग-अलग इंटरफेस / प्रकार के हो सकते हैं और उस इंटरफ़ेस को अलग तरीके से लागू कर सकते हैं। यह हमें वस्तुओं को स्थानापन्न करने की अनुमति देता है, जिससे हमें यह चुनने में मदद मिलती है कि कौन सा उपयोग करना है। बहुरूपता के रूप में भी जाना जाता है।

क्लाइंट को केवल इंटरफ़ेस के बारे में पता होगा और कार्यान्वयन नहीं होगा।

तो एक अंतरफलक के लिए सार प्रोग्रामिंग में इस तरह के रूप सार वर्ग के कुछ प्रकार बनाने शामिल होगा Shapeकेवल निर्दिष्ट यानी इंटरफेस के साथ draw(), getCoordinates(), getArea()आदि .. और फिर विभिन्न ठोस वर्ग इस तरह के एक सर्किल वर्ग, स्क्वायर वर्ग, त्रिभुज वर्ग के रूप में उन इंटरफेस को लागू किया है। इसलिए एक कार्यान्वयन के लिए एक अंतरफलक के लिए कार्यक्रम।


0

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

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