"एक इंटरफेस के लिए प्रोग्रामिंग" समझना


29

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

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

जावा में एक सामान्य उदाहरण, उपयोग करना है:

List myList = new ArrayList();के बजाय ArrayList myList = new ArrayList();

इस बारे में मेरे दो सवाल हैं:

  1. मैं यह सुनिश्चित करना चाहता हूं कि मैं इस दृष्टिकोण के मुख्य लाभों को समझता हूं। मुझे लगता है कि लाभ ज्यादातर लचीलेपन के हैं। एक ठोस कार्यान्वयन के बजाय एक वस्तु को अधिक उच्च-स्तरीय संदर्भ के रूप में घोषित करना, विकास चक्र के दौरान और पूरे कोड में अधिक लचीलेपन और बनाए रखने की अनुमति देता है। क्या ये सही है? क्या लचीलापन मुख्य लाभ है?

  2. क्या 'प्रोग्रामिंग टू ए इंटरफ़ेस' के और भी तरीके हैं? या "एक ठोस कार्यान्वयन के बजाय एक इंटरफ़ेस के रूप में एक चर घोषित कर रहा है" इस अवधारणा का एकमात्र कार्यान्वयन है?

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


संभव है कि डुप्लिकेट उपयोगी क्यों हैं?
ग्नत


1
इस उत्तर आप एक आसान उदाहरण समझने के लिए देता है programmers.stackexchange.com/a/314084/61852
Tulains Córdova

जवाबों:


44

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

यह सही नहीं है । या कम से कम, यह पूरी तरह से सही नहीं है।

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

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

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


जवाब के लिए धन्यवाद। आपने जो लिखा है, उसे देखते हुए मुझे लगता है कि मैं समझता हूं कि "इंटरफ़ेस के लिए प्रोग्रामिंग" का क्या मतलब है और इसके क्या लाभ हैं। लेकिन मेरा एक प्रश्न है - इस अवधारणा का सबसे सामान्य ठोस उदाहरण यह है: किसी वस्तु का संदर्भ बनाते समय, संदर्भ प्रकार को इस प्रकार लागू करते हैं जैसे कि यह ऑब्जेक्ट लागू होता है (या सुपरक्लास यह ऑब्जेक्ट विरासत में मिला है), संदर्भ प्रकार बनाने के बजाय वस्तु प्रकार। (उर्फ, के List myList = new ArrayList()बजाय ArrayList myList = new ArrayList()। (प्रश्न अगली टिप्पणी में है)
अविव कोहन

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

6
संList/ ArrayListनहीं है कि मैं क्या बात कर रहा हूँ। यह Employeeएक कर्मचारी रिकॉर्ड को संग्रहीत करने के लिए आपके द्वारा उपयोग किए गए लिंक किए गए तालिकाओं के सेट के बजाय एक वस्तु प्रदान करने जैसा है । या गानों के माध्यम से पुनरावृत्ति करने के लिए एक इंटरफ़ेस प्रदान करना, और उन गानों को फेरबदल करना, या सीडी पर, या इंटरनेट से स्ट्रीमिंग करना, न करना। वे सिर्फ गाने का एक क्रम हैं।
तेलस्टिन

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

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

18

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

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

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

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

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


यह एक अच्छी बात है, और मैं इसे कुछ संदर्भों में बहुत सुनता हूं।
तेलस्टिन

में तुम्हारी बात समझ रहा हूँ। तो मुझे यह देखने दें कि क्या आप सामान्य प्रोग्रामिंग के लिए कह रहे हैं जिसे मैं अनुकूलित कर सकता हूं: मान लीजिए कि मेरे पास एक वर्ग (ए) है जो अमूर्त वर्ग बी की कार्यक्षमता का उपयोग करता है। वर्ग सी और डी विरासत वर्ग बी - वे उस के लिए ठोस कार्यान्वयन प्रदान करते हैं क्लास करने के लिए कहा जाता है। यदि क्लास ए सीधे क्लास सी या डी का उपयोग करता है, तो उसे 'प्रोग्रामिंग से एक कार्यान्वयन' कहा जाता है, जो बहुत लचीला समाधान नहीं है। लेकिन अगर क्लास ए, क्लास बी के संदर्भ का उपयोग करता है, जिसे बाद में सी कार्यान्वयन या डी कार्यान्वयन के लिए सेट किया जा सकता है, तो यह चीजों को अधिक लचीला और बनाए रखता है। क्या ये सही है?
अवीव कोहन

यदि यह सही है, तो मेरा प्रश्न यह है - क्या an एक इंटरफेस के लिए प्रोग्रामिंग ’के लिए और अधिक ठोस उदाहरण हैं, एक ठोस-संदर्भ के बजाय concrete एक इंटरफ़ेस संदर्भ का उपयोग करके’ आम उदाहरण के अलावा?
अवीव कोहन

2
@AvivCohn इस उत्तर में थोड़ी देर से, लेकिन एक ठोस उदाहरण विश्व व्यापी वेब है। ब्राउज़र वार्स (IE 4 युग) के दौरान वेब साइटों को किसी भी विनिर्देशन के बारे में नहीं लिखा गया था, लेकिन कुछ ब्राउज़र (नेटस्केप या IE) की quirks के लिए। यह मूल रूप से इंटरफ़ेस के बजाय कार्यान्वयन के लिए प्रोग्रामिंग था।
सेबस्टियन रेडल

9

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

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

उदाहरण के लिए, एक ILoggerइंटरफ़ेस पर विचार करें जिसे वर्तमान में एक ठोस LogToEmailLoggerवर्ग के रूप में लागू किया गया है । LogToEmailLoggerवर्ग सभी को उजागर करता है ILoggerतरीकों और गुण, लेकिन यह भी एक कार्यान्वयन-विशिष्ट संपत्ति के लिए होता है sysAdminEmail

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

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

इस अर्थ में, एक अंतरफलक युग्मन युग्मन कोडिंग ।

आपके दूसरे बिंदु के बारे में: एक और कारण जो मैंने इंटरफ़ेस में कोडिंग के लिए देखा है वह है कोड की जटिलता को कम करना।

उदाहरण के लिए, कल्पना मैं निम्नलिखित इंटरफेस के साथ एक खेल है I2DRenderable, I3DRenderable, IUpdateable। यह एकल गेम घटकों के लिए 2 डी और 3 डी रेंडर करने योग्य सामग्री के लिए असामान्य नहीं है। अन्य घटक केवल 2 डी और अन्य केवल 3 डी हो सकते हैं।

यदि 2 डी रेंडरिंग एक मॉड्यूल द्वारा किया जाता है, तो यह I2DRenderableएस के संग्रह को बनाए रखने के लिए समझ में आता है । इससे कोई फर्क नहीं पड़ता कि इसके संग्रह में वस्तुएं भी हैं I3DRenderableया IUpdatebleअन्य मॉड्यूल के रूप में वस्तुओं के उन पहलुओं के उपचार के लिए जिम्मेदार होंगे।

I2DRenderableरेंडरिंग क्लास की जटिलता को कम रखने के लिए रेंडर करने योग्य वस्तुओं को एक सूची के रूप में संग्रहीत करना । 3 डी रेंडरिंग और अपडेट लॉजिक इसकी चिंता का विषय नहीं है और इसलिए इसके बच्चों की वस्तुओं के उन पहलुओं को नजरअंदाज किया जा सकता है।

इस अर्थ में, एक इंटरफेस को कोडिंग चिंताओं को अलग करके जटिलता को कम रखता है ।


4

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

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

यह तब आपको अपने आंतरिक कोड को फिर से भरने की सुविधा प्रदान करता है जबकि अन्य सभी चीजों को नहीं बताना है जो इसके इंटरफेस पर निर्भर करती हैं।

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

जैसा कि @Doval इस उत्तर पर टिप्पणियों में बताते हैं कि त्रुटियों की स्थानीयता भी है। मुझे लगता है कि सभी एनकैप्सुलेशन को उबालते हैं। जिस तरह आप ऑब्जेक्ट ओरिएंटेड डिज़ाइन में वस्तुओं के लिए इसका उपयोग करेंगे, उसी प्रकार यह अवधारणा उच्च स्तर पर भी उपयोगी है।


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

4

एक वास्तविक विश्व सादृश्य मदद कर सकता है:

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

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

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

यही इंटरफेस आपको मिलता है।
एकरूपता की जटिलताओं की आवश्यकता के बिना एकीकृत व्यवहार जिसे ऑब्जेक्ट के कई अलग-अलग वर्गों द्वारा किया जा सकता है ।


1

शब्द "एक इंटरफेस के लिए प्रोग्रामिंग" बहुत व्याख्या के लिए खुला है। सॉफ्टवेयर डेवलपमेंट में इंटरफेस एक बहुत ही सामान्य शब्द है। यहां बताया गया है कि मैं उन जूनियर डेवलपर्स को कैसे समझाऊं जिन्हें मैंने वर्षों से प्रशिक्षित किया है।

सॉफ्टवेयर वास्तुकला में प्राकृतिक सीमाओं की एक विस्तृत श्रृंखला है। आम उदाहरणों में शामिल हैं

  • क्लाइंट और सर्वर प्रक्रियाओं के बीच नेटवर्क सीमा
  • एक अनुप्रयोग और एक तीसरे पक्ष के पुस्तकालय के बीच एपीआई सीमा
  • कार्यक्रम के भीतर विभिन्न व्यावसायिक डोमेन के बीच आंतरिक कोड सीमा

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

इसके परिणाम निम्न हैं:

  • जब तक वे विनिर्देश लागू करते हैं तब तक बाहरी घटकों का आदान-प्रदान किया जा सकता है
  • सही व्यवहार को मान्य करने के लिए यूनिट परीक्षणों के लिए प्राकृतिक बिंदु
  • एकीकरण परीक्षण महत्वपूर्ण हो गए - क्या विनिर्देश अस्पष्ट था?
  • एक डेवलपर के रूप में आपके पास किसी विशेष कार्य पर काम करते समय चिंता की एक छोटी सी दुनिया होती है

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

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