मेरे पास ढीले युग्मन और इंटरफेस के बारे में एक वैचारिक/सैद्धांतिक प्रश्न है।

तो एक इंटरफ़ेस का उपयोग करने का एक तरीका एक निश्चित कन्स्ट्रक्टर द्वारा आवश्यक पैरामीटर को समाहित करना हो सकता है:

class Foo
{
    public Foo(IFooInterface foo)
    {
       // do stuff that depends on the members of IFooInterface
    }
}

तो जब तक वस्तु अनुबंध को लागू करती है, तब तक सब कुछ काम करेगा। मेरी समझ से यहां मुख्य लाभ यह है कि यह बहुरूपता को सक्षम बनाता है, लेकिन मुझे यकीन नहीं है कि इसका वास्तव में ढीले युग्मन से कोई लेना-देना है या नहीं।

आइए तर्क के लिए कहें कि एक IFooInterface इस प्रकार है:

interface IFooInterface
{
   string FooString { get; set; }
   int FooInt { get; set; }

   void DoFoo(string _str); 
}

एक ढीले युग्मन दृष्टिकोण से, उपरोक्त कन्स्ट्रक्टर में IFooInterface का उपयोग न करना बेहतर नहीं होगा, और इसके बजाय फू को इस तरह सेट अप करें:

class Foo
{
    public Foo(string _fooString, int _fooInt, Action<string> _doFoo)
    {
       // do the same operations
    }
}

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

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

    public static Func<T, R> Wrap<T, R>(Func<T, object[]> conversion)
    {
        return new Func<T, R>(t =>
        {
            object[] parameters = conversion(t);

            Type[] args = new Type[parameters.Length];

            for (int i = 0; i < parameters.Length; i++)
            {
                args[i] = parameters[i].GetType();
            }

            ConstructorInfo info = typeof(R).GetConstructor(args);

            return (R)info.Invoke(parameters);
        });
    }

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

public Foo MakeFoo(IFooInterface foo)
{
    return Wrap<IFooInterface, Foo>(f => 
       new object[] { f.FooString, f.FooInt, f.DoFoo })(foo);  
}

मैंने इस बारे में चर्चा सुनी है कि इंटरफेस को ढीले-युग्मन को सक्षम करने के लिए कैसे माना जाता है, लेकिन इस बारे में सोच रहा था।

आश्चर्य है कि कुछ अनुभवी प्रोग्रामर क्या सोचते हैं।

3
Sean Thoman 24 जून 2011, 04:51
लूज कपलिंग का लक्ष्य यह नहीं है कि न तो पक्ष में दूसरे का संदर्भ होना चाहिए। इंटरफेस एक (बहुत) उपयोगी भाषा विशेषता है। उन्हें टालने का कोई कारण नहीं है।
 – 
Kirk Woll
24 जून 2011, 05:18
ढीले युग्मन की मेरी धारणा यह है कि मुझे एक वर्ग (या अधिक संक्षेप में गुणों/व्यवहारों का एक सेट) लेने में सक्षम होना चाहिए और किसी विशेष संदर्भ के बावजूद इसके उद्देश्य को समझना चाहिए, या, जैसा कि मैंने कहा कि इसे किसी अन्य प्रोजेक्ट में छोड़ दें और न देखें संदेशों का समूह जैसे "प्रकार या नामस्थान x नहीं मिला"। मेरा सवाल यह नहीं है कि क्या हमें इंटरफेस से बचना चाहिए, मेरा सवाल यह है कि क्या वे वास्तव में ढीले युग्मन को बढ़ावा देने के लिए हैं, या क्या वे बहुरूपता/विरासत के लिए हैं?
 – 
Sean Thoman
24 जून 2011, 05:24
सभी कोड एक निश्चित संदर्भ में मौजूद हैं। ढीले युग्मन का मतलब है कि एक वर्ग को उस वर्ग के अंतरंग विवरण जानने की आवश्यकता नहीं है जिस पर वह निर्भर करता है। इंटरफेस यह स्पष्ट करने में मदद कर सकते हैं कि किसी वर्ग के सार्वजनिक सदस्य सार्वजनिक उपभोग के लिए क्या हैं और कौन से कार्यान्वयन-विशिष्ट हैं।
 – 
dahlbyk
24 जून 2011, 05:33

2 जवाब

सबसे बढ़िया उत्तर

मेरा पहला विचार यह है कि आपने क्रमशः FooString और FooInt के सेटर्स के लिए Action<string> और Action<int> प्रदान नहीं किया। IFooInterface के कार्यान्वयन में उन सेटर्स से संबंधित नियम हो सकते हैं, और इंटरफ़ेस पर उजागर नहीं किए गए अन्य कार्यान्वयन विवरणों तक पहुंच की आवश्यकता हो सकती है।

उसी तरह, आपको एक Func<string> और Func<int> को भी स्वीकार करना चाहिए: IFooInterface के कार्यान्वयन में इस बारे में नियम हो सकते हैं कि FooString और FooInt समय के अनुसार क्या हैं आगे बढ़ता है। उदाहरण के लिए, DoFoo उन मानों की पुनर्गणना कर सकता है; आप यह नहीं मान सकते हैं कि वे केवल उन क्षेत्रों के लिए पास-थ्रू हैं जो कभी नहीं बदलते हैं।

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

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

इसे दूसरे तरीके से रखने के लिए, आप मुझे नूडल्स, सॉस, सब्जियां और हैमबर्गर दे सकते हैं, लेकिन यह स्पेगेटी और मीटबॉल नहीं है :-)

2
Bryan Watts 24 जून 2011, 05:32

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

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

3
dahlbyk 24 जून 2011, 05:25
मुझे लगता है कि मुझे जो मिल रहा है, वह यह है कि भले ही आप किसी विशिष्ट कार्यान्वयन के लिए कोडिंग नहीं कर रहे हों, आप एक वाक्यात्मक अनुबंध के लिए कोडिंग कर रहे हैं। तो अनुबंध के लिए अभी भी तंग-युग्मन है, जो निश्चित रूप से कार्यान्वयन के लिए तंग-युग्मन से बेहतर है, लेकिन फिर भी युग्मन शुरू कर रहा है। मुझे लगता है कि कुछ मामलों में बहुत अधिक ढीले युग्मन की संभावना हो सकती है, लेकिन मुझे लगता है कि इसके विपरीत ढीले से तंग में परिवर्तन करना आसान होगा।
 – 
Sean Thoman
24 जून 2011, 05:36
खैर, किसी बिंदु पर आपको किसी चीज़ पर निर्भर रहना पड़ता है। बिंदु जितना संभव हो उतना कम निर्भर होना है। यदि कोई इंटरफ़ेस करेगा तो किसी वर्ग पर निर्भर न रहें। जब एक 2-विधि इंटरफ़ेस करेगा तो 20-विधि इंटरफ़ेस पर निर्भर न रहें। वगैरह।
 – 
dahlbyk
24 जून 2011, 05:38
@ सीन, अगर पहिए आपकी कार से नहीं जुड़े होते, तो यह कहीं नहीं जाता।
 – 
Dan Bryant
24 जून 2011, 05:40
सच है कि मैं मानता हूं कि आपको किसी चीज पर निर्भर रहना पड़ता है, लेकिन प्राइमेटिव से चिपके रहना निश्चित रूप से "जितना संभव हो उतना कम" का उपयोग करने के योग्य है, क्या आपको नहीं लगता? एक विधि के मापदंडों या एक निर्माता के मापदंडों के हस्ताक्षर अनिवार्य रूप से अपने आप में एक अनुबंध हैं, ऐसा मुझे लगता है। हालांकि इस पद्धति का उपयोग करने के लिए एक लागत है, मैं स्वीकार करता हूं, संभावित रूप से पठनीयता और संभावित रूप से जटिल चीजों को चोट पहुंचाने में। साथ ही मुझे यकीन नहीं है कि मेरे द्वारा वर्णित तरीके से इंटरफेस वास्तव में कितनी बार उपयोग किया जा रहा है (गुण + व्यवहार, या अधिक व्यवहार करने के लिए?)
 – 
Sean Thoman
24 जून 2011, 05:53
आप बिल्कुल सही हैं - इंटरफेस अक्सर व्यवहार के लिए उपयोग किए जाते हैं, राज्य नहीं। आदिम मापदंडों का एक संग्रह सिर्फ राज्य है, इस प्रकार एक पैरामीटर ऑब्जेक्ट के लिए एक इंटरफ़ेस का उपयोग करना शायद समझ में नहीं आता है।
 – 
dahlbyk
24 जून 2011, 07:10