जब आपको किसी एक गुण की आवश्यकता न हो तो इंटरफ़ेस लागू करना


31

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

int IFoo.Bar
{
    get { raise new NotImplementedException(); }
}

मुझे लगता है कि इसमें कुछ भी गलत नहीं है, प्रति se, लेकिन यह "सही" महसूस नहीं करता है। क्या इससे पहले भी कोई और ऐसी ही स्थिति में आया है? यदि हां, तो आपने इसे कैसे अपनाया?


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

मुझे निश्चित रूप से यह देखने में दिलचस्पी होगी, अगर आप इसे पा सकते हैं।
क्रिस प्रैट

23
मैं .NET के पुस्तकालय में इसके कई मामलों को इंगित कर सकता हूं - और ये सभी बिग्रेड मिस्टेक के रूप में मान्यता प्राप्त हैं । यह लिस्कोव सबस्टीट्यूशन सिद्धांत का एक प्रतिष्ठित और आम उल्लंघन है - एलएसपी का उल्लंघन करने के कारणों को मेरे जवाब में यहां
जिमी होफा

3
क्या आपको इस विशिष्ट इंटरफ़ेस को लागू करने की आवश्यकता है, या क्या आप एक सुपरनोटफेस को लागू कर सकते हैं और इसका उपयोग कर सकते हैं?
क्रिस्टोफर शुल्त्स

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

जवाबों:


51

यह एक शास्त्रीय उदाहरण है कि लोग किस तरह से लिस्कोव सबस्ट्रेशन सिद्धांत का उल्लंघन करने का निर्णय लेते हैं। मैं दृढ़ता से इसे हतोत्साहित करता हूं लेकिन संभवतः एक अलग समाधान को प्रोत्साहित करेगा:

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

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


यहाँ विकिपीडिया से कुछ त्वरित बिट्स दिए गए हैं:

Liskov प्रतिस्थापन सिद्धांत को केवल "पूर्व स्थितियों को मजबूत न करें, और बाद की स्थितियों को कमजोर न करें" के रूप में तैयार किया जा सकता है।

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

एक ही अनुबंध के विभिन्न कार्यान्वयनों के बीच सिमेंटिक इंटरऑपरेबिलिटी और प्रतिस्थापन के लिए - आपको उन सभी को समान व्यवहार करने की आवश्यकता है।


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

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


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

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

4

मुझे ठीक लगता है, अगर यह आपकी स्थिति है।

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

अस्वीकरण: इसके लिए ठीक से करने के लिए कई विरासत की आवश्यकता होती है, और मुझे पता नहीं है कि C # समर्थन करता है या नहीं।


6
C # कक्षाओं के कई उत्तराधिकार का समर्थन नहीं करता है, लेकिन यह इंटरफेस के लिए इसका समर्थन करता है।
mgw854

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


4

मैं इस स्थिति में आया हूं। वास्तव में जैसा कि कहीं और बताया गया है बीसीएल ऐसे मामलों ... मैं बेहतर उदाहरण प्रदान करते हैं और कुछ औचित्य प्रदान करने के लिए कोशिश करता हूँ गया है:

जब आपके पास पहले से ही भेज दिया गया इंटरफ़ेस है जिसे आप संगतता कारणों से रखते हैं और ...

  • इंटरफ़ेस में ऐसे सदस्य शामिल हैं जो अप्रचलित या अस्वीकृत हैं। उदाहरण के लिए BlockingCollection<T>.ICollection.SyncRoot(दूसरों के बीच) जबकि ICollection.SyncRootप्रति से अधिक अप्रचलित नहीं है, यह फेंक देगा NotSupportedException

  • इंटरफ़ेस में ऐसे सदस्य होते हैं जिन्हें वैकल्पिक होने के लिए प्रलेखित किया जाता है, और कार्यान्वयन अपवाद को फेंक सकते हैं। उदाहरण के लिए MSDN पर IEnumerator.Resetइसके बारे में कहते हैं:

रीसेट विधि COM इंटरऑपरेबिलिटी के लिए प्रदान की जाती है। इसे लागू करने की आवश्यकता नहीं है; इसके बजाय, कार्यान्वयनकर्ता बस NotSupportedException को फेंक सकता है।

  • इंटरफ़ेस के डिज़ाइन की गलती से, यह पहली जगह में एक से अधिक इंटरफ़ेस होना चाहिए था। बीसीएल के साथ कंटेनरों के केवल संस्करणों को लागू करने के लिए यह एक सामान्य पैटर्न है NotSupportedException। मैंने इसे स्वयं किया है, यह वही है जो अब अपेक्षित है ... मैं ICollection<T>.IsReadOnlyवापसी करता हूं trueताकि आप उन्हें बता सकें। सही डिज़ाइन में इंटरफ़ेस का पठनीय संस्करण होना चाहिए था, और फिर पूर्ण इंटरफ़ेस उसी से विरासत में मिला।

  • उपयोग करने के लिए कोई बेहतर इंटरफ़ेस नहीं है। उदाहरण के लिए, मेरे पास एक वर्ग है जो आपको अनुक्रमणिका द्वारा आइटम एक्सेस करने की अनुमति देता है, जांचें कि क्या इसमें कोई आइटम है और किस सूचकांक पर, इसका कुछ आकार है, आप इसे किसी सरणी में कॉपी कर सकते हैं ... यह IList<T>मेरे लिए एक नौकरी लगती है एक निश्चित आकार, और जोड़ने या हटाने का समर्थन नहीं करता है, इसलिए यह सूची की तुलना में एक सरणी की तरह अधिक काम करता है। लेकिन बीसीएल में नहीं IArray<T>है

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


यह भी विचार करें कि यह समर्थित क्यों नहीं है?

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

कभी-कभी एक डिफ़ॉल्ट मूल्य समझ में आता है। उदाहरण के लिए ICollection<T>.IsReadOnly, ऊपर उल्लेख किया गया है, यह मामले के आधार पर ´true´ या ´false´ को वापस करने के लिए समझ में आता है। तो ... का शब्दार्थ क्या है IFoo.Bar? लौटने के लिए शायद कुछ समझदार डिफ़ॉल्ट मूल्य हो।


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


0

क्या इससे पहले भी कोई और ऐसी ही स्थिति में आया है?

हाँ, .Net पुस्तकालय डिजाइनरों ने किया। शब्दकोश वर्ग वह करता है जो आप कर रहे हैं। यह आईडीबीआई के कुछ तरीकों को प्रभावी ढंग से छिपाने के लिए स्पष्ट कार्यान्वयन का उपयोग करता है । इसे यहां बेहतर तरीके से समझाया गया है , लेकिन संक्षेप में, डिक्शनरी के ऐड, कॉपीटू, या हटाने के तरीकों का उपयोग करने के लिए, जो KeyValuePairs लेते हैं, आपको सबसे पहले ऑब्जेक्ट को एक IDEDIA में डालना होगा।

* यह शब्द "छिपाने" के सख्त अर्थ में तरीकों को "छिपाना" नहीं है क्योंकि Microsoft इसका उपयोग करता है । लेकिन मैं इस उदाहरण में एक बेहतर शब्द नहीं जानता।


... जो भयानक है।
मोनिका

क्यों होता है पतन?
user2023861

2
शायद इसलिए कि आपने सवाल का जवाब नहीं दिया। Ish। की तरह।
मोनिका

@LightnessRacesinOrbit, मैंने इसे और अधिक स्पष्ट करने के लिए अपना उत्तर अपडेट किया। मुझे उम्मीद है कि इससे ओपी को मदद मिलेगी।
user2023861

2
ऐसा लगता है जैसे यह मेरे लिए सवाल का जवाब देता है। तथ्य यह है कि यह एक अच्छा या बुरा विचार हो सकता है प्रश्न के दायरे में नहीं लगता है, लेकिन संकेत देने के लिए अभी भी उपयोगी हो सकता है।
एल्सडिल

-6

आप हमेशा एक सौम्य मान या डिफ़ॉल्ट मान लागू कर सकते हैं और वापस कर सकते हैं। आखिर यह सिर्फ एक संपत्ति है। यह 0 (int की डिफ़ॉल्ट संपत्ति), या जो कुछ भी मूल्य आपके कार्यान्वयन (int.MinValue, int.MaxValue, 1, 42, आदि) में वापस कर सकता है ...

//We don't officially implement this property
int IFoo.Bar
{
     { get; }
}

एक अपवाद को फेंकना बुरे रूप की तरह लगता है।


2
क्यूं कर? गलत डेटा को किसी भी बेहतर तरीके से कैसे लौटाया जाता है?
मोनिका

1
यह एलएसपी को तोड़ता है: जिमी होफा के जवाब को स्पष्टीकरण के लिए क्यों देखें।

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

मैं अब कैसे मान गलत होगा जब आपके एक इंटरफ़ेस को लागू करने! यह आपका कार्यान्वयन है, यह आप जो चाहें कर सकते हैं।
जॉन रेन्नोर

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