तो, स्पष्ट रूप से एक इंटरफ़ेस को लागू करने के लिए एक अच्छा उपयोग मामला क्या है?
क्या यह केवल इतना है कि वर्ग का उपयोग करने वाले लोगों को उन सभी तरीकों / गुणों पर गौर करने की ज़रूरत नहीं है?
तो, स्पष्ट रूप से एक इंटरफ़ेस को लागू करने के लिए एक अच्छा उपयोग मामला क्या है?
क्या यह केवल इतना है कि वर्ग का उपयोग करने वाले लोगों को उन सभी तरीकों / गुणों पर गौर करने की ज़रूरत नहीं है?
जवाबों:
यदि आप एक ही विधि और अलग-अलग कार्यान्वयन के साथ दो इंटरफेस लागू करते हैं, तो आपको स्पष्ट रूप से लागू करना होगा।
public interface IDoItFast
{
void Go();
}
public interface IDoItSlow
{
void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
void IDoItFast.Go()
{
}
void IDoItSlow.Go()
{
}
}
यह गैर-पसंदीदा सदस्य को छिपाने के लिए उपयोगी है। उदाहरण के लिए, यदि आप दोनों को लागू करते हैं IComparable<T>
और IComparable
यह आमतौर पर IComparable
लोगों को यह आभास नहीं देने के लिए ओवरलोड को छिपाने के लिए अच्छा है कि आप विभिन्न प्रकार की वस्तुओं की तुलना कर सकते हैं। इसी तरह, कुछ इंटरफेस सीएलएस-अनुपालन नहीं हैं, जैसे IConvertible
, यदि आप इंटरफ़ेस को स्पष्ट रूप से लागू नहीं करते हैं , तो उन भाषाओं के अंतिम उपयोगकर्ता जिनके लिए सीएलएस अनुपालन की आवश्यकता होती है, वे आपके ऑब्जेक्ट का उपयोग नहीं कर सकते हैं। (अगर बीसीएल कार्यान्वयनकर्ताओं ने आदिम सदस्यों के गैर-परिवर्तनीय सदस्यों को छिपाया नहीं तो यह बहुत विनाशकारी होगा))
एक और दिलचस्प नोट यह है कि आम तौर पर इस तरह के निर्माण का उपयोग करने का मतलब है कि एक इंटरफ़ेस को स्पष्ट रूप से लागू करने वाली संरचना केवल इंटरफ़ेस प्रकार के लिए बॉक्सिंग करके उन्हें आमंत्रित कर सकती है। आप सामान्य बाधाओं का उपयोग करके इसे प्राप्त कर सकते हैं ::
void SomeMethod<T>(T obj) where T:IConvertible
जब आप इसे पास करेंगे तो एक इंट को बॉक्स नहीं करेंगे।
string
जेनरिक से पहले चारों ओर था और यह प्रथा प्रचलन में थी। जब .net 2 के आसपास आया string
तो वे सार्वजनिक इंटरफ़ेस को तोड़ना नहीं चाहते थे, इसलिए उन्होंने इसे चारों ओर छोड़ दिया क्योंकि यह जगह में सुरक्षा के साथ था।
एक इंटरफ़ेस को स्पष्ट रूप से लागू करने के लिए कुछ अतिरिक्त कारण:
पश्चगामी संगतता : यदि ICloneable
इंटरफ़ेस बदल जाता है, तो विधि वर्ग के सदस्यों को लागू करने के लिए अपनी विधि के हस्ताक्षर नहीं बदलने होंगे।
क्लीनर कोड : यदि Clone
ICloneable से विधि को हटा दिया जाता है, तो एक संकलक त्रुटि होगी , हालाँकि यदि आप इस पद्धति को कार्यान्वित करते हैं तो आप अप्रयुक्त 'अनाथ' सार्वजनिक तरीकों से समाप्त हो सकते हैं
मजबूत टाइपिंग : एक उदाहरण के साथ सुपरकैट की कहानी को स्पष्ट करने के लिए, यह मेरा पसंदीदा नमूना कोड होगा, इसे ICloneable
स्पष्ट रूप से लागू करने की अनुमति देता Clone()
है जब आप इसे सीधे MyObject
उदाहरण के सदस्य के रूप में कहते हैं :
public class MyObject : ICloneable
{
public MyObject Clone()
{
// my cloning logic;
}
object ICloneable.Clone()
{
return this.Clone();
}
}
interface ICloneable<out T> { T Clone(); T self {get;} }
। ध्यान दें कि ICloneable<T>
टी। पर जानबूझकर कोई बाधा नहीं है। जबकि एक वस्तु को आम तौर पर केवल सुरक्षित रूप से क्लोन किया जा सकता है यदि इसका आधार हो सकता है, तो कोई एक आधार वर्ग से प्राप्त करना चाह सकता है जिसे सुरक्षित रूप से उस वर्ग का एक ऑब्जेक्ट क्लोन किया जा सकता है जो नहीं कर सकता है। इसके लिए अनुमति देने के लिए, मैं अनुशंसा करूंगा कि अंतर्निहित वर्ग एक सार्वजनिक क्लोन पद्धति को उजागर करें। इसके बजाय एक protected
क्लोनिंग विधि के साथ अंतर्निहित कक्षाएं हैं और सीलबंद कक्षाएं जो उनसे निकलती हैं और सार्वजनिक क्लोनिंग को उजागर करती हैं।
एक अन्य उपयोगी तकनीक एक फ़ंक्शन के सार्वजनिक कार्यान्वयन के लिए एक मान वापस करना है जो एक इंटरफ़ेस में निर्दिष्ट से अधिक विशिष्ट है।
उदाहरण के लिए, कोई वस्तु कार्यान्वित कर सकती है ICloneable
, लेकिन फिर भी उसकी सार्वजनिक रूप से दिखाई देने वाली Clone
विधि अपना ही प्रकार लौटाती है।
इसी तरह, IAutomobileFactory
एक Manufacture
विधि हो सकती है जो एक रिटर्न देती है Automobile
, लेकिन एक FordExplorerFactory
, जो लागू होती है IAutomobileFactory
, उसकी Manufacture
विधि वापस आ सकती है FordExplorer
(जो कि प्राप्त होती है Automobile
)। कोड जो जानता है कि यह टाइपकास्ट किए बिना वापस लौटाए गए ऑब्जेक्ट पर -pecific गुणों का FordExplorerFactory
उपयोग कर सकता है , जबकि कोड जो केवल यह जानता था कि यह किसी प्रकार का था बस एक के रूप में अपनी वापसी के साथ सौदा करेगा ।FordExplorer
FordExplorerFactory
IAutomobileFactory
Automobile
यह तब भी उपयोगी है जब आपके पास एक ही सदस्य के नाम और हस्ताक्षर के साथ दो इंटरफेस हों, लेकिन इसका उपयोग कैसे करना है, इसके आधार पर इसके व्यवहार को बदलना चाहते हैं। (मैं इस तरह कोड लिखने की सलाह नहीं देता):
interface Cat
{
string Name {get;}
}
interface Dog
{
string Name{get;}
}
public class Animal : Cat, Dog
{
string Cat.Name
{
get
{
return "Cat";
}
}
string Dog.Name
{
get
{
return "Dog";
}
}
}
static void Main(string[] args)
{
Animal animal = new Animal();
Cat cat = animal; //Note the use of the same instance of Animal. All we are doing is picking which interface implementation we want to use.
Dog dog = animal;
Console.WriteLine(cat.Name); //Prints Cat
Console.WriteLine(dog.Name); //Prints Dog
}
public class Animal : Cat, Dog
यह एक इंटरफ़ेस को स्पष्ट रूप से लागू करने के लिए सार्वजनिक इंटरफ़ेस क्लीनर रख सकता है, अर्थात आपका File
वर्ग स्पष्ट रूप से लागू कर सकता है IDisposable
और एक सार्वजनिक विधि प्रदान Close()
कर सकता है जो उपभोक्ता की तुलना में अधिक समझ में आता है Dispose(
)।
F # केवल स्पष्ट इंटरफ़ेस कार्यान्वयन प्रदान करता है, इसलिए आपको हमेशा अपनी कार्यक्षमता तक पहुंचने के लिए विशेष इंटरफ़ेस में डालना होगा, जो इंटरफ़ेस के बहुत स्पष्ट (बिना किसी उद्देश्य के) उपयोग के लिए बनाता है।
Dispose
वे हैं जिन्हें कभी भी सफाई की आवश्यकता नहीं होगी); एक बेहतर उदाहरण एक अपरिवर्तनीय संग्रह के कार्यान्वयन की तरह होगा IList<T>.Add
।
यदि आपके पास एक आंतरिक इंटरफ़ेस है और आप अपने वर्ग के सदस्यों को सार्वजनिक रूप से लागू नहीं करना चाहते हैं, तो आप उन्हें स्पष्ट रूप से लागू करेंगे। सार्वजनिक रूप से कार्यान्वयन को लागू करने की आवश्यकता है।
स्पष्ट कार्यान्वयन के लिए एक और कारण के लिए है रख-रखाव ।
जब एक वर्ग "व्यस्त" हो जाता है - हाँ ऐसा होता है, हम सभी के पास अन्य टीम के सदस्यों के कोड को फिर से लाने का लक्जरी नहीं है - तो एक स्पष्ट कार्यान्वयन होने से यह स्पष्ट होता है कि एक इंटरफ़ेस अनुबंध को संतुष्ट करने के लिए एक विधि है।
तो यह कोड की "पठनीयता" में सुधार करता है।
#region
एक उपयुक्त शीर्षक स्ट्रिंग के साथ यही है। और विधि पर एक टिप्पणी।
द्वारा एक अलग उदाहरण दिया जाता है System.Collections.Immutable
, जिसमें लेखकों ने इंटरफ़ेस के उन हिस्सों को दूर करते हुए संग्रह प्रकारों के लिए एक परिचित एपीआई को संरक्षित करने के लिए तकनीक का उपयोग करने का विकल्प चुना जो अपने नए प्रकारों के लिए कोई अर्थ नहीं रखते हैं।
वस्तुतः, ImmutableList<T>
औजार IList<T>
और इस प्रकार ICollection<T>
( क्रम में अनुमति देने के लिए ImmutableList<T>
अभी तक, विरासत कोड के साथ और अधिक आसानी से इस्तेमाल किया जा करने के लिए) void ICollection<T>.Add(T item)
एक के लिए कोई मतलब नहीं है ImmutableList<T>
अपरिवर्तनीय सूची में कोई तत्व जोड़ मौजूदा सूची में परिवर्तन नहीं करना चाहिए, के बाद से: ImmutableList<T>
भी व्युत्पन्न से IImmutableList<T>
जिसका IImmutableList<T> Add(T item)
के लिए इस्तेमाल किया जा सकता अपरिवर्तनीय सूचियाँ।
इस प्रकार के मामले में Add
, कार्यान्वयन ImmutableList<T>
इस प्रकार दिख रहा है:
public ImmutableList<T> Add(T item)
{
// Create a new list with the added item
}
IImmutableList<T> IImmutableList<T>.Add(T value) => this.Add(value);
void ICollection<T>.Add(T item) => throw new NotSupportedException();
int IList.Add(object value) => throw new NotSupportedException();
स्पष्ट रूप से परिभाषित इंटरफेस के मामले में, सभी विधियां स्वचालित रूप से निजी हैं, आप उन तक पहुँच संशोधक सार्वजनिक नहीं दे सकते। मान लीजिए:
interface Iphone{
void Money();
}
interface Ipen{
void Price();
}
class Demo : Iphone, Ipen{
void Iphone.Money(){ //it is private you can't give public
Console.WriteLine("You have no money");
}
void Ipen.Price(){ //it is private you can't give public
Console.WriteLine("You have to paid 3$");
}
}
// So you have to cast to call the method
class Program
{
static void Main(string[] args)
{
Demo d = new Demo();
Iphone i1 = (Iphone)d;
i1.Money();
((Ipen)i1).Price();
Console.ReadKey();
}
}
// You can't call methods by direct class object
यह है कि हम स्पष्ट इंटरफ़ेस कैसे बना सकते हैं: यदि हमारे पास 2 इंटरफ़ेस हैं और दोनों इंटरफ़ेस में एक ही विधि है और एक एकल वर्ग इन 2 इंटरफेस को इनहेरिट करता है, तो जब हम एक इंटरफ़ेस विधि को कॉल करते हैं तो कंपाइलर भ्रमित हो जाता है कि किस विधि को बुलाया जाए, इसलिए हम कर सकते हैं स्पष्ट इंटरफ़ेस का उपयोग करके इस समस्या का प्रबंधन करें। यहाँ एक उदाहरण मैंने नीचे दिया है।
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace oops3
{
interface I5
{
void getdata();
}
interface I6
{
void getdata();
}
class MyClass:I5,I6
{
void I5.getdata()
{
Console.WriteLine("I5 getdata called");
}
void I6.getdata()
{
Console.WriteLine("I6 getdata called");
}
static void Main(string[] args)
{
MyClass obj = new MyClass();
((I5)obj).getdata();
Console.ReadLine();
}
}
}