एकल, अमूर्त वर्ग और इंटरफेस की भूमिकाएं क्या हैं?


13

मैं C ++ में OOP का अध्ययन कर रहा हूं और भले ही मुझे इन 3 अवधारणाओं की परिभाषाओं के बारे में पता हो, लेकिन मैं वास्तव में यह महसूस नहीं कर सकता कि इसका उपयोग कब या कैसे करना है।

आइए इस वर्ग का उपयोग उदाहरण के लिए करें:

class Person{
    private:
             string name;
             int age;
    public:
             Person(string p1, int p2){this->name=p1; this->age=p2;}
             ~Person(){}

             void set_name (string parameter){this->name=parameter;}                 
             void set_age (int parameter){this->age=parameter;}

             string get_name (){return this->name;}
             int get_age (){return this->age;}

             };

1. सिंगलटन

वर्ग का प्रतिबंध केवल एक वस्तु के काम करने के लिए कैसे होता है?

क्या आप एक ऐसी कक्षा डिजाइन कर सकते हैं जिसमें केवल 2 उदाहरण होंगे? या शायद 3?

जब सिफारिश की / आवश्यक एक सिंगलटन का उपयोग कर रहा है? क्या यह अच्छा अभ्यास है?

2. सार वर्ग

जहाँ तक मुझे पता है, यदि केवल एक शुद्ध आभासी कार्य है, तो कक्षा सार हो जाती है। इसलिए, जोड़ना

virtual void print ()=0;

क्या यह सही होगा?

आपको ऐसे वर्ग की आवश्यकता क्यों होगी जिसकी वस्तु की आवश्यकता नहीं है?

3.Interface

यदि एक इंटरफ़ेस एक अमूर्त वर्ग है जिसमें सभी विधियाँ शुद्ध आभासी कार्य हैं, तो

उनमें से 2 के बीच मुख्य अंतर क्या है?

अग्रिम में धन्यवाद!


2
सिंगलटन विवादास्पद है, विभिन्न राय प्राप्त करने के लिए इस साइट पर एक खोज करें।
विंस्टन एवर्ट

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

1
कृपया एक बार में एक।
जेएफओ

जवाबों:


17

1. सिंगलटन

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

एक ऐसी कक्षा का निर्माण करना जिसमें केवल 2 या 3 उदाहरण होंगे, पूरी तरह से संभव है। जब भी आपको पूरे सिस्टम में उस वर्ग का केवल एक उदाहरण होने की आवश्यकता महसूस हो, आपको सिंगलटन का उपयोग करना चाहिए। यह आमतौर पर उन वर्गों के लिए होता है जिनके पास 'प्रबंधक' व्यवहार होता है।

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

इस पैटर्न के बारे में कुछ अच्छी और बुरी बातें जरूर हैं लेकिन यह चर्चा कहीं और की है।

2. सार वर्ग

हाँ य़ह सही हैं। केवल एक आभासी विधि कक्षा को सार के रूप में चिह्नित करेगी।

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

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

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

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

3. इंटरफेस

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

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

आप एक बेहतर विचार के लिए MSDN में C # के इंटरफ़ेस विनिर्देश के बारे में पढ़ सकते हैं:

http://msdn.microsoft.com/en-us/library/ms173156.aspx

C ++ शुद्ध अमूर्त वर्ग होने से उसी तरह का व्यवहार प्रदान करेगा।


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

@StevenBurnap: लेकिन C ++ में नहीं, जो प्रश्न का संदर्भ है।
डेडएमजेड

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


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

8

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

सिंगलेट्स - जब आप चाहते हैं कि सभी कॉलिंग कोड किसी भी कारण से चर का उपयोग करें, तो आपके पास निम्नलिखित विकल्प हैं:

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

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

तो आप एक सिंगलटन का उपयोग कहां करेंगे? यहाँ कुछ उदाहरण हैं:

  • लॉगिंग - यदि आप चाहते हैं कि आपकी पूरी प्रक्रिया में एक ही लॉग हो, तो आप एक लॉग ऑब्जेक्ट बना सकते हैं और इसे हर जगह पास कर सकते हैं। लेकिन क्या होगा यदि आपके पास विरासत एप्लिकेशन कोड की 100,000k लाइनें हैं? उन सभी को संशोधित करें? या आप बस निम्नलिखित का परिचय दे सकते हैं और कृपया इसे कहीं भी उपयोग करना शुरू करें:

    CLog::GetInstance().write( "my log message goes here" );
  • सर्वर कनेक्शन कैश - यह कुछ ऐसा था जिसे मुझे हमारे आवेदन में पेश करना था। हमारा कोड आधार, और इसका बहुत कुछ था, जब भी प्रसन्न होता है, सर्वर से जुड़ता था। अधिकांश समय यह ठीक था, जब तक कि नेटवर्क में किसी प्रकार की विलंबता नहीं थी। हमें एक समाधान की आवश्यकता थी और 10 साल पुराने आवेदन का नया स्वरूप वास्तव में मेज पर नहीं था। मैंने एक सिंगलटन CServerConnectionManager लिखा। तब मैंने कोड के माध्यम से खोज की और समान हस्ताक्षर कॉल के साथ CoCreateInstanceWithAuth कॉल को प्रतिस्थापित किया जिसने मेरी कक्षा का आह्वान किया। पहले प्रयास के बाद कनेक्शन बंद हो गया था और बाकी समय "कनेक्ट" प्रयास तात्कालिक थे। कुछ लोग कहते हैं कि सिंगलटन बुरे हैं। मैं कहता हूं कि उन्होंने मेरे बट को बचाया।

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

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

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

अगला विषय ... इंटरफेस और अमूर्त वर्ग। जैसा कि दूसरों ने उल्लेख किया है, इंटरफ़ेस एक सार वर्ग है, लेकिन यह इस बात से परे है कि यह बिल्कुल कोई कार्यान्वयन नहीं है। कुछ भाषाओं में इंटरफ़ेस कीवर्ड भाषा का हिस्सा है। C ++ में हम बस अमूर्त कक्षाओं का उपयोग करते हैं। Microsoft VC ++ ने आंतरिक रूप से इसे परिभाषित करने के लिए एक कदम उठाया:

typedef struct interface;

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

तो आप इसका उपयोग कहां करेंगे? आइए चल रहे ऑब्जेक्ट टेबल के अपने उदाहरण पर वापस जाएं। मान लीजिए कि आधार वर्ग ने ...

आभासी शून्य प्रिंट () = 0;

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

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

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

interface ILogger {
    virtual void write( const char* format, ... ) = 0;
};

class CLog : public ILogger { ... };

class CDbLog : public ILogger { ... };

class CLogFactory {
    ILogger* GetLog();
};

यदि सभी कोड ILogger इंटरफ़ेस का उपयोग कर रहे थे, तो मुझे सभी को बदलना होगा CLogFactory का आंतरिक कार्यान्वयन :: GetLog ()। एक उंगली उठाने के लिए मेरे बिना बाकी कोड केवल स्वचालित रूप से काम करेंगे।

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


4

जब सिफारिश की / आवश्यक एक सिंगलटन का उपयोग कर रहा है? क्या यह अच्छा अभ्यास है?

कभी नहीँ। इससे भी बदतर, वे छुटकारा पाने के लिए एक निरपेक्ष कुतिया हैं, इसलिए यह गलती एक बार आपको कई, कई वर्षों तक परेशान कर सकती है।

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


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

1
@StevenBurnap: शायद किसी और भाषा में।
डेडएमजेड

4
"इंटरफ़ेस" C ++ में एक सम्मेलन है। जब मैंने इसका उपयोग देखा है, तो यह केवल शुद्ध आभासी विधियों और गुणों के साथ एक सार वर्ग है। जाहिर है आप किसी भी पुराने वर्ग को लिख सकते हैं और नाम के सामने एक "I" लगा सकते हैं।
रोबोट

इस तरह से मुझे उम्मीद है कि लोग इस पोस्ट का जवाब देंगे। एक बार में एक सवाल। वैसे भी, अपने ज्ञान को साझा करने के लिए बहुत धन्यवाद दोस्तों। यह समुदाय समय बिताने के लायक है।
appoll

3

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

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

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

आपके पास एक अमूर्त वर्ग भी हो सकता है, जहाँ सभी विधियाँ कार्यान्वित की जाती हैं, लेकिन आप इसे सार के रूप में चिह्नित करते हैं, यह इंगित करने के लिए उपयोग नहीं किया जाना चाहिए कि यह उपवर्ग के बिना नहीं है।

नोट: इंटरफ़ेस और अमूर्त वर्ग C ++ दुनिया में कई विरासतों आदि के साथ बहुत अलग नहीं हैं, लेकिन जावा एट अल में अलग-अलग अर्थ हैं।


बहुत सही कहा! +1
jmort253

3

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

कहें कि हमारे पास पायथन कोड जैसा एक कार्य है:

function foo(objs):
    for obj in objs:
        obj.printToScreen()

class HappyWidget:
    def printToScreen(self):
        print "I am a happy widget"

class SadWidget:
    def printToScreen(self):
        print "I am a sad widget"

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

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

यदि हम अजगर की तरह एक गतिशील, बतख-टाइप भाषा के बारे में बात कर रहे थे, तो हम अब तक खत्म कर देंगे। हालाँकि, C ++ का स्टैटिक टाइप सिस्टम यह मांग करता है कि हम अपने फंक्शन में ऑबजेक्सेस को एक क्लास देते हैं और यह केवल उस शुरुआती क्लास के सबक्लासेस के साथ काम करने में सक्षम होगा।

void foo( Printable *objs[], int n){ //Please correctme if I messed up on the type signature
    for(int i=0; i<n; i++){
        objs[i]->printToScreen();
    }
}

हमारे मामले में, मुद्रण योग्य वर्ग के मौजूद होने का एकमात्र कारण है प्रिंटोस्क्रीन स्क्रीन के अस्तित्व के लिए जगह देना। चूँकि PrintToScreen पद्धति को लागू करने वाले वर्गों के बीच कोई साझा कार्यान्वयन नहीं है, यह Printable को एक अमूर्त वर्ग में बनाने के लिए समझ में आता है जो केवल एक समान पदानुक्रम में समान वर्गों के समूह के लिए एक तरीके के रूप में उपयोग किया जाता है।

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

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


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


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


1

इंटरफेस

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

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

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

यदि आप पहली बार में चतुर थे, तो आपने इसे देखा होगा और सीधे csv को बचाने के लिए कॉल नहीं किए। इसके बजाय आप सोचेंगे कि इसे करने के लिए आपको क्या करना चाहिए, कोई फर्क नहीं पड़ता कि इसे कैसे लागू किया गया था। आइए कहते हैं store()और retrieve()। आप एक बनाने Persisterके लिए सार तरीकों के साथ इंटरफेस store()और retrieve()और एक बनाने के CsvPersisterउपवर्ग है कि वास्तव में उन तरीकों लागू करता है।

बाद में, आप DbPersisterडेटा का वास्तविक संग्रहण और पुनर्प्राप्ति पूरी तरह से अलग तरीके से बना सकते हैं कि आपके सीएसवी वर्ग ने यह कैसे किया।

बड़ी बात यह है कि अब आपको बस इतना करना है कि बदलाव हो

Persister* prst = new CsvPersister();

सेवा

Persister* prst = new DbPersister();

और फिर आप कर रहे हैं। आपके कॉल prst.store()और prst.retrieve()सभी अभी भी काम करेंगे, वे "पर्दे के पीछे" अलग तरह से संभाले हुए हैं।

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

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

आप हो सकता है Array, LinkedList, BinaryTree, आदि सभी उपवर्गों Containerजो तरह के तरीकों है insert(), find(), delete()

अब किसी लिंक की गई सूची के बीच में कुछ जोड़ने पर, आपको यह भी जानने की जरूरत नहीं है कि लिंक की गई सूची क्या है। आप बस कॉल करते हैं myLinkedList->insert(4)और यह जादुई रूप से सूची के माध्यम से पुनरावृत्ति करता है और इसे वहां चिपका देता है। यहां तक ​​कि अगर आप जानते हैं कि एक लिंक की गई सूची कैसे काम करती है (जो आपको वास्तव में चाहिए), तो आपको इसके विशिष्ट कार्यों को देखने की जरूरत नहीं है, क्योंकि आप शायद पहले से ही जानते हैं कि वे एक अलग Containerपहले का उपयोग करने से क्या हैं ।

सार वर्ग

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

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

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

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

एकमात्र

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

यहाँ कुछ अधिक अनुभवी और सावधान लोगों से वैश्विक राज्य पर एक अच्छी चर्चा है: ग्लोबल स्टेट इतना ईविल क्यों है?


1

पशु साम्राज्य में विभिन्न जानवर हैं जो स्तनधारी हैं। यहाँ स्तनपायी एक आधार वर्ग है और विभिन्न जानवर इससे प्राप्त होते हैं।

क्या आपने कभी किसी स्तनपायी को चलते देखा है? हां, कई बार मुझे यकीन है - हालांकि वे सभी प्रकार के स्तनपायी नहीं थे?

आपने कभी ऐसा कुछ नहीं देखा, जो वस्तुतः सिर्फ एक स्तनपायी प्राणी था। वे सभी प्रकार के स्तनधारी थे।

वर्ग स्तनपायी को विभिन्न विशेषताओं और समूहों को परिभाषित करने की आवश्यकता होती है, लेकिन यह एक भौतिक इकाई के रूप में मौजूद नहीं है।

इसलिए यह एक सार आधार वर्ग है।

स्तनधारी कैसे चलते हैं? क्या वे चलते हैं, तैरते हैं, उड़ते हैं आदि?

स्तनपायी स्तर पर पता करने का कोई तरीका नहीं है लेकिन सभी स्तनधारियों को किसी न किसी तरह से चलना चाहिए (आइए हम कहते हैं कि उदाहरण को आसान बनाने के लिए यह एक जैविक कानून है)।

इसलिए MoveAround () एक वर्चुअल फ़ंक्शन है क्योंकि इस वर्ग से निकलने वाले प्रत्येक स्तनपायी को इसे अलग तरीके से लागू करने में सक्षम होने की आवश्यकता होती है।

हालाँकि, प्रत्येक स्तनपायी के रूप में MUST मूव को चारों ओर से परिभाषित करता है क्योंकि सभी स्तनधारियों को स्थानांतरित होना चाहिए और इसे स्तनपायी स्तर पर करना असंभव है। इसे सभी बाल वर्गों द्वारा लागू किया जाना चाहिए लेकिन इसका आधार वर्ग से कोई मतलब नहीं है।

इसलिए MoveAround एक शुद्ध वर्चुअल फ़ंक्शन है।

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

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