मार्कर इंटरफ़ेस का उद्देश्य क्या है?
मार्कर इंटरफ़ेस का उद्देश्य क्या है?
जवाबों:
यह "मिच गेहूं" की प्रतिक्रिया के आधार पर एक स्पर्शरेखा है।
आमतौर पर, जब भी मैं लोगों को फ्रेमवर्क डिज़ाइन दिशानिर्देशों का हवाला देता हूं, मैं हमेशा इसका उल्लेख करना चाहता हूं:
आपको आमतौर पर ज्यादातर समय रूपरेखा डिजाइन दिशानिर्देशों को अनदेखा करना चाहिए।
यह फ्रेमवर्क डिज़ाइन दिशानिर्देशों के साथ किसी भी समस्या के कारण नहीं है। मुझे लगता है कि .NET फ्रेमवर्क एक शानदार क्लास लाइब्रेरी है। फ्रेमवर्क डिज़ाइन दिशानिर्देशों से बहुत सारी शानदारता बहती है।
हालाँकि, डिज़ाइन दिशानिर्देश अधिकांश प्रोग्रामर द्वारा लिखे गए अधिकांश कोड पर लागू नहीं होते हैं। उनका उद्देश्य लाखों डेवलपर्स द्वारा उपयोग किए जाने वाले एक बड़े ढांचे के निर्माण को सक्षम करना है, न कि पुस्तकालय लेखन को अधिक कुशल बनाना।
इसमें बहुत सारे सुझाव आपको उन चीजों को करने के लिए मार्गदर्शन कर सकते हैं जो:
.Net फ्रेमवर्क बड़ा है, वास्तव में बड़ा है। यह इतना बड़ा है कि यह मानना बिल्कुल अनुचित होगा कि किसी को भी इसके हर पहलू के बारे में विस्तृत जानकारी है। वास्तव में, यह मान लेना अधिक सुरक्षित है कि अधिकांश प्रोग्रामर अक्सर उस ढांचे के कुछ हिस्सों का सामना करते हैं जो उन्होंने पहले कभी इस्तेमाल नहीं किया है।
उस स्थिति में, API डिज़ाइनर के प्राथमिक लक्ष्य निम्न हैं:
फ्रेमवर्क डिज़ाइन दिशानिर्देश उन लक्ष्यों को पूरा करने वाले कोड बनाने के लिए डेवलपर्स को धक्का देते हैं।
इसका मतलब है कि विरासत की परतों से बचने जैसी चीजें करना, भले ही इसका मतलब कोड को डुप्लिकेट करना हो, या साझा सहायकों का उपयोग करने के बजाय सभी अपवाद कोड को "प्रवेश बिंदु" पर धकेलना हो (ताकि स्टैक के निशान डीबगर में अधिक समझ में आए), और बहुत कुछ इसी तरह की अन्य चीजों के बारे में।
प्राथमिक दिशानिर्देश जो उन दिशानिर्देशों को मार्कर इंटरफेस के बजाय विशेषताओं का उपयोग करने का सुझाव देते हैं, क्योंकि मार्कर इंटरफेस को हटाने से कक्षा पुस्तकालय की विरासत संरचना बहुत अधिक अप्राप्य हो जाती है। 15 प्रकार और पदानुक्रम की 2 परतों के साथ वंशानुक्रम पदानुक्रम की 30 परतों के साथ एक वर्ग आरेख बहुत चुनौतीपूर्ण है।
यदि आपके API का उपयोग करने वाले लाखों डेवलपर हैं, या आपका कोड आधार वास्तव में बड़ा है (100K LOC से अधिक) तो उन दिशानिर्देशों का पालन करने से बहुत मदद मिल सकती है।
यदि 5 मिलियन डेवलपर 15 मिनट खर्च करने के बजाय एक एपीआई सीखने में 60 मिनट खर्च करते हैं, तो इसका परिणाम 428 मानव वर्षों की शुद्ध बचत है। वह बहुत समय है।
हालाँकि, अधिकांश परियोजनाओं में लाखों डेवलपर या 100K + LOC शामिल नहीं होते हैं। एक विशिष्ट परियोजना में, 4 डेवलपर्स और लगभग 50K लोको के साथ, मान्यताओं का सेट बहुत अलग है। टीम के डेवलपर्स को बेहतर समझ होगी कि कोड कैसे काम करता है। इसका मतलब है कि यह उच्च गुणवत्ता वाले कोड को जल्दी से बनाने के लिए अनुकूलन करने के लिए बहुत अधिक समझ में आता है, और बग की मात्रा को कम करने और परिवर्तन करने के लिए आवश्यक प्रयास के लिए।
1 सप्ताह का विकासशील कोड जो कि .net फ्रेमवर्क के अनुरूप है, बनाम 8 घंटे का कोड लिखना जो बदलना आसान है और जिसमें कम कीड़े हैं, में परिणाम हो सकते हैं:
4,999,999 के बिना अन्य डेवलपर्स लागत को अवशोषित करने के लिए आमतौर पर इसके लायक नहीं है।
उदाहरण के लिए, मार्कर इंटरफेस के लिए परीक्षण एक एकल "अभिव्यक्ति" के लिए नीचे आता है, और कम कोड में परिणाम होता है जो विशेषताओं की तलाश में है।
तो मेरी सलाह है:
virtual protected
टेम्पलेट विधि का नामकरण करना बहुत अतिरिक्त काम नहीं है और आप स्पष्ट रूप से संवाद करते हैं कि यह एक टेम्पलेट विधि है ... IMNSHO, जो लोग एपीआई पर विचार किए बिना आवेदन लिखते हैं ( ) बिल्कुल वही लोग हैं जो बहुत सारे नकल करते हैं ( और भी undocumented और आमतौर पर अपठनीय) कोड, चारों ओर अन्य तरीके से नहीं। DoSomethingCore
DoSomething
But.. I'm not a framework developer, I don't care about my API!
मार्कर इंटरफेस का उपयोग रन-टाइम में एक विशिष्ट इंटरफ़ेस को लागू करने के रूप में एक वर्ग की क्षमता को चिह्नित करने के लिए किया जाता है।
इंटरफेस डिजाइन और नेट प्रकार डिजाइन दिशानिर्देश - इंटरफेस डिजाइन सी # में विशेषताओं का उपयोग करने के पक्ष में मार्कर इंटरफेस के उपयोग को हतोत्साहित, लेकिन जैसा कि @Jay Bazuzi बताते हैं, यह विशेषताओं के लिए की तुलना में मार्कर इंटरफेस के लिए जाँच करने के लिए आसान है:o is I
तो इसके बजाय:
public interface IFooAssignable {}
public class FooAssignableAttribute : IFooAssignable
{
...
}
.NET दिशानिर्देशों ने सिफारिश की है कि आप ऐसा करते हैं:
public class FooAssignableAttribute : Attribute
{
...
}
[FooAssignable]
public class Foo
{
...
}
चूंकि हर दूसरे जवाब में कहा गया है कि "उन्हें टाला जाना चाहिए", इसलिए इसका स्पष्टीकरण देना उपयोगी होगा।
सबसे पहले, मार्कर इंटरफेस का उपयोग क्यों किया जाता है: वे उस कोड की अनुमति देने के लिए मौजूद हैं जो उस ऑब्जेक्ट का उपयोग कर रहा है जो यह जांचने के लिए लागू करता है कि क्या वे उक्त इंटरफ़ेस को लागू करते हैं और ऑब्जेक्ट को अलग तरीके से मानते हैं।
इस दृष्टिकोण के साथ समस्या यह है कि यह एनकैप्सुलेशन को तोड़ता है। वस्तु का अब खुद पर अप्रत्यक्ष नियंत्रण है कि इसे बाहरी रूप से कैसे उपयोग किया जाएगा। इसके अलावा, इसे उस प्रणाली का ज्ञान है जिसका उपयोग करने जा रहा है। मार्कर इंटरफ़ेस को लागू करने से, वर्ग परिभाषा यह सुझाव दे रही है कि इसका उपयोग कहीं न कहीं होने की उम्मीद है जो मार्कर के अस्तित्व की जांच करता है। इसमें उपयोग किए गए वातावरण का निहित ज्ञान है और यह परिभाषित करने की कोशिश कर रहा है कि इसका उपयोग कैसे किया जाना चाहिए। यह एनकैप्सुलेशन के विचार के खिलाफ जाता है क्योंकि इसमें सिस्टम के एक हिस्से के कार्यान्वयन का ज्ञान है जो पूरी तरह से अपने दायरे से बाहर मौजूद है।
व्यावहारिक स्तर पर यह पोर्टेबिलिटी और पुन: प्रयोज्य को कम करता है। यदि क्लास को एक अलग एप्लिकेशन में फिर से उपयोग किया जाता है, तो इंटरफ़ेस को भी कॉपी करने की आवश्यकता होती है, और नए वातावरण में इसका कोई अर्थ नहीं हो सकता है, जिससे यह पूरी तरह से निरर्थक हो जाता है।
जैसे, "मार्कर" वर्ग के बारे में मेटाडेटा है। इस मेटाडेटा का उपयोग केवल कक्षा द्वारा ही नहीं किया जाता है और यह केवल (कुछ!) बाहरी क्लाइंट कोड के लिए सार्थक होता है ताकि यह एक निश्चित तरीके से वस्तु का इलाज कर सके। क्योंकि इसका केवल क्लाइंट कोड से मतलब है, मेटाडेटा क्लाइंट कोड में होना चाहिए, न कि क्लास एपीआई के लिए।
"मार्कर इंटरफ़ेस" और सामान्य इंटरफ़ेस के बीच का अंतर यह है कि विधियों वाला एक इंटरफ़ेस बाहरी दुनिया को बताता है कि इसका उपयोग कैसे किया जा सकता है जबकि एक खाली इंटरफ़ेस का अर्थ है कि यह बाहरी दुनिया को बता रहा है कि इसका उपयोग कैसे किया जाना चाहिए।
IConstructableFromString<T>
निर्दिष्ट करता है कि एक वर्ग T
केवल तभी लागू कर सकता है IConstructableFromString<T>
जब उसके पास एक स्थिर सदस्य हो ...
public static T ProduceFromString(String params);
, इंटरफ़ेस के लिए एक साथी वर्ग एक विधि की पेशकश कर सकता है public static T ProduceFromString<T>(String params) where T:IConstructableFromString<T>
; यदि क्लाइंट कोड में एक विधि होती है T[] MakeManyThings<T>() where T:IConstructableFromString<T>
, तो कोई भी नए प्रकार को परिभाषित कर सकता है जो क्लाइंट कोड के साथ काम कर सकता है ताकि उनसे निपटने के लिए क्लाइंट कोड को संशोधित किया जा सके। यदि मेटाडेटा क्लाइंट कोड में था, तो मौजूदा क्लाइंट द्वारा उपयोग के लिए नए प्रकार बनाना संभव नहीं होगा।
T
उपयोग करने वाले वर्ग के बीच का अनुबंध वह होता है IConstructableFromString<T>
जहां आपके पास इंटरफ़ेस में एक विधि होती है जो कुछ व्यवहार का वर्णन करती है इसलिए यह एक मार्कर इंटरफ़ेस नहीं है।
ProduceFromString
उपरोक्त उदाहरण में स्थैतिक विधि को खोजने और निष्पादित करने की वास्तविक प्रक्रिया शामिल नहीं होगी। किसी भी तरह से इंटरफ़ेस, सिवाय इसके कि इंटरफ़ेस का उपयोग मार्कर के रूप में किया जाएगा ताकि यह इंगित किया जा सके कि आवश्यक फ़ंक्शन को लागू करने के लिए किन वर्गों से अपेक्षा की जानी चाहिए।
मार्कर इंटरफेस कभी-कभी एक आवश्यक बुराई हो सकता है जब कोई भाषा भेदभावपूर्ण संघ प्रकारों का समर्थन नहीं करती है ।
मान लीजिए कि आप एक ऐसी विधि को परिभाषित करना चाहते हैं जो एक तर्क की अपेक्षा करता है जिसका प्रकार ए, बी, या सी में से एक होना चाहिए। कई कार्यात्मक-प्रथम भाषाओं (जैसे एफ # ) में, इस प्रकार को स्पष्ट रूप से परिभाषित किया जा सकता है:
type Arg =
| AArg of A
| BArg of B
| CArg of C
हालाँकि, O # पहली भाषाओं में जैसे C #, यह संभव नहीं है। यहां कुछ समान हासिल करने का एकमात्र तरीका इंटरफ़ेस आईएआरजी और इसके साथ "मार्क" ए, बी और सी को परिभाषित करना है।
बेशक, आप "इंटरफ़ेस" को तर्क के रूप में स्वीकार करके मार्कर इंटरफ़ेस का उपयोग करने से बच सकते हैं, लेकिन तब आप स्पष्टता और कुछ प्रकार की सुरक्षा खो देंगे।
विभेदित संघ प्रकार अत्यंत उपयोगी हैं और कम से कम 30 वर्षों से कार्यात्मक भाषाओं में मौजूद हैं। अजीब बात है, आज तक, सभी मुख्यधारा की ओओ भाषाओं ने इस सुविधा की अनदेखी की है - हालांकि इसका वास्तव में प्रति कार्यात्मक कार्यात्मक प्रोग्रामिंग से कोई लेना-देना नहीं है, लेकिन यह प्रकार प्रणाली से संबंधित है।
Foo<T>
प्रत्येक प्रकार के लिए स्थैतिक फ़ील्ड का एक अलग सेट होगा T
, एक जेनेरिक वर्ग के लिए कठिन नहीं होता है जिसमें स्थिर फ़ील्ड होते हैं जिनमें प्रतिनिधि प्रक्रिया करने के लिए प्रतिनिधि होते हैं T
, और उन फ़ील्ड्स को प्री-पॉप्युलेट करते हैं जो हर प्रकार के वर्ग को संभालने के लिए कार्य करते हैं के साथ काम करना चाहिए प्रकार पर एक सामान्य इंटरफ़ेस बाधा का उपयोग करना T
संकलक समय पर जांच करेगा कि आपूर्ति प्रकार कम से कम वैध होने का दावा करता है, भले ही यह सुनिश्चित करने में सक्षम नहीं होगा कि यह वास्तव में था।
एक मार्कर इंटरफ़ेस सिर्फ एक इंटरफ़ेस है जो खाली है। एक वर्ग इस इंटरफ़ेस को किसी कारण से उपयोग किए जाने वाले मेटाडेटा के रूप में लागू करेगा। C # में आप आमतौर पर उन विशेषताओं के लिए एक वर्ग को चिह्नित करने के लिए विशेषताओं का उपयोग करेंगे जिनके लिए आप अन्य भाषाओं में एक मार्कर इंटरफ़ेस का उपयोग करेंगे।
एक मार्कर इंटरफ़ेस एक वर्ग को इस तरह से टैग करने की अनुमति देता है जो सभी वंशजों पर लागू होगा। एक "शुद्ध" मार्कर इंटरफ़ेस कुछ भी परिभाषित या विरासत में नहीं मिलेगा; एक और उपयोगी प्रकार के मार्कर इंटरफेस एक हो सकते हैं जो एक और इंटरफ़ेस "विरासत में मिला" लेकिन कोई नया सदस्य परिभाषित नहीं करता है। उदाहरण के लिए, यदि कोई इंटरफ़ेस "IReadableFoo" है, तो एक इंटरफ़ेस "IImmutableFoo" को भी परिभाषित कर सकता है, जो "Foo" की तरह व्यवहार करेगा, लेकिन जो कोई भी इसका उपयोग करता है, उससे वादा करेगा कि इसका मूल्य नहीं बदलेगा। एक दिनचर्या जो एक IImmutableFoo को स्वीकार करती है वह इसे IReadableFoo के रूप में उपयोग करने में सक्षम होगी, लेकिन दिनचर्या केवल उन वर्गों को स्वीकार करेगी जिन्हें IImmutableFoo लागू करने के रूप में घोषित किया गया था।
मैं "शुद्ध" मार्कर इंटरफेस के लिए बहुत सारे उपयोगों के बारे में नहीं सोच सकता। केवल एक ही मैं सोच सकता हूं कि यदि EqualityComparer (T का) .Default Object.Equals को किसी भी प्रकार के लिए लौटाएगा, जिसने IDoNotUseEqualityComparer को लागू किया है, भले ही वह प्रकार IEquotComparer लागू हो। यह Liskov प्रतिस्थापन सिद्धांत का उल्लंघन किए बिना एक अपरिवर्तनीय अपरिवर्तनीय प्रकार की अनुमति देगा: यदि यह प्रकार समानता-परीक्षण से संबंधित सभी तरीकों को सील करता है, तो एक व्युत्पन्न प्रकार अतिरिक्त फ़ील्ड जोड़ सकता है और उन्हें उत्परिवर्तित कर सकता है, लेकिन ऐसे फ़ील्ड का उत्परिवर्तन नहीं होगा ' किसी भी आधार-प्रकार के तरीकों का उपयोग करके दृश्यमान नहीं होना चाहिए। एक असुरक्षित अपरिवर्तनीय वर्ग के लिए यह भयानक नहीं हो सकता है और या तो EqualityComparer.Default या विश्वास प्राप्त वर्गों के किसी भी उपयोग से बचना चाहिए ताकि IEqualityComparer को लागू न किया जा सके,
ये दो विस्तार विधियां अधिकांश मुद्दों को हल करेंगी स्कॉट विशेषताओं पर पक्ष-विपक्ष इंटरफेस का दावा करते हैं:
public static bool HasAttribute<T>(this ICustomAttributeProvider self)
where T : Attribute
{
return self.GetCustomAttributes(true).Any(o => o is T);
}
public static bool HasAttribute<T>(this object self)
where T : Attribute
{
return self != null && self.GetType().HasAttribute<T>()
}
अब आपके पास है:
if (o.HasAttribute<FooAssignableAttribute>())
{
//...
}
बनाम:
if (o is IFooAssignable)
{
//...
}
मैं यह देखने में विफल रहा कि एक एपीआई का निर्माण स्कॉट के दावों की तुलना में दूसरे की तुलना में पहले पैटर्न के साथ 5 गुना लंबा होगा।
मार्कर इंटरफ़ेस कुल रिक्त इंटरफ़ेस है जिसका कोई निकाय / डेटा-सदस्य / कार्यान्वयन नहीं है। जब आवश्यकता होती है
एक वर्ग मार्कर इंटरफ़ेस लागू करता है, यह सिर्फ " निशान " करने के लिए है; इसका अर्थ है कि यह जेवीएम को बताता है कि विशेष वर्ग क्लोनिंग के उद्देश्य से है इसलिए इसे क्लोन करने की अनुमति दें। यह विशेष वर्ग अपनी वस्तुओं को क्रमबद्ध करने के लिए है, इसलिए कृपया अपनी वस्तुओं को क्रमबद्ध करने की अनुमति दें।
मार्कर इंटरफ़ेस वास्तव में OO भाषा में केवल एक प्रक्रियात्मक प्रोग्रामिंग है। एक इंटरफ़ेस एक मार्कर इंटरफ़ेस को छोड़कर, कार्यान्वयनकर्ताओं और उपभोक्ताओं के बीच एक अनुबंध को परिभाषित करता है, क्योंकि एक मार्कर इंटरफ़ेस कुछ भी नहीं बल्कि खुद को परिभाषित करता है। इसलिए, गेट के ठीक बाहर, मार्कर इंटरफ़ेस एक इंटरफ़ेस होने के मूल उद्देश्य में विफल रहता है।