कंस्ट्रक्टर इंजेक्शन क्या है?


47

(सेवा लोकेटर) डिजाइन पैटर्न पर लेखों के माध्यम से जाते समय मैं कंस्ट्रक्टर इंजेक्शन और निर्भरता इंजेक्शन देख रहा हूं।

जब मैंने कंस्ट्रक्टर इंजेक्शन के बारे में जाना, तो मुझे अस्पष्ट परिणाम मिले, जिसने मुझे यहां जांचने के लिए प्रेरित किया।

कंस्ट्रक्टर इंजेक्शन क्या है? क्या यह एक विशिष्ट प्रकार की निर्भरता इंजेक्शन है? एक विहित उदाहरण एक बड़ी मदद होगी!

संपादित करें

एक हफ्ते के अंतराल के बाद इस सवाल पर फिर से गौर करते हुए, मैं देख सकता हूं कि मैं कितना खो गया था ... बस अगर किसी और के यहाँ पॉप होता है, तो मैं थोड़ा सीखने के साथ प्रश्न शरीर को अपडेट करूंगा। कृपया टिप्पणी / सही करने के लिए स्वतंत्र महसूस करें। कंस्ट्रक्टर इंजेक्शन और प्रॉपर्टी इंजेक्शन डिपेंडेंसी इंजेक्शन दो प्रकार के होते हैं।


5
Google में पहली हिट स्पष्ट रूप से यह बताती है ... misko.hevery.com/2009/02/19/…
user281377

जवाबों:


95

मैं कोई विशेषज्ञ नहीं हूं, लेकिन मुझे लगता है कि मैं मदद कर सकता हूं। और हाँ, यह एक विशिष्ट प्रकार की निर्भरता इंजेक्शन है।

डिस्क्लेमर: लगभग यह सब निनजेक्ट विकी से "चुराया" गया था

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

class Sword 
{
    public void Hit(string target)
    {
        Console.WriteLine("Chopped {0} clean in half", target);
    }
}

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

class Samurai
{
    readonly Sword sword;
    public Samurai() 
    {
        this.sword = new Sword();
    }

    public void Attack(string target)
    {
        this.sword.Hit(target);
    }
}

अब, हम अपने समुराई बना सकते हैं और लड़ाई कर सकते हैं!

class Program
{
    public static void Main() 
    {
        var warrior = new Samurai();
        warrior.Attack("the evildoers");
    }
}

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

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

interface IWeapon
{
    void Hit(string target);
}

फिर, हमारा Sword वर्ग इस इंटरफ़ेस को लागू कर सकता है:

class Sword : IWeapon
{
    public void Hit(string target) 
    {
        Console.WriteLine("Chopped {0} clean in half", target);
    }
}

और हम अपने समुराई वर्ग को बदल सकते हैं:

class Samurai
{
    readonly IWeapon weapon;
    public Samurai() 
    {
        this.weapon = new Sword();
    }
    public void Attack(string target) 
    {
        this.weapon.Hit(target);
    }
}

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

सौभाग्य से, एक आसान उपाय है। समुराई के निर्माणकर्ता के भीतर से तलवार बनाने के बजाय, हम इसे निर्माणकर्ता के पैरामीटर के रूप में उजागर कर सकते हैं। कंस्ट्रक्टर इंजेक्शन के रूप में भी जाना जाता है।

class Samurai
{
    readonly IWeapon weapon;
    public Samurai(IWeapon weapon) 
    {
        this.weapon = weapon;
    }
    public void Attack(string target) 
    {
        this.weapon.Hit(target);
    }
}

जैसा कि जियोर्जियो ने बताया, संपत्ति इंजेक्शन भी है। यह कुछ इस तरह होगा:

class Samurai
{
    IWeapon weapon;

    public Samurai() { }


    public void SetWeapon(IWeapon weapon)
    {
        this.weapon = weapon;
    }

    public void Attack(string target) 
    {
        this.weapon.Hit(target);
    }

}

उम्मीद है की यह मदद करेगा।


8
यह एक प्यार करता था! :) यह वास्तव में एक कहानी की तरह पढ़ा जाता है! बस उत्सुक। यदि आप एक ही समुराई को कई हथियारों (क्रमिक रूप से) के साथ बांटना चाहते थे, तो संपत्ति का इंजेक्शन सबसे अच्छा तरीका होगा?
TheSilverBullet 12

हां, आप ऐसा कर सकते हैं। वास्तव में, मुझे लगता है कि आप IWeapon को आक्रमण विधि के एक पैरामीटर के रूप में पारित करना बेहतर होगा। जैसे "सार्वजनिक शून्य हमला (IWeapon with, string target)"। और डुप्लिकेट कोड से बचने के लिए मैं मौजूदा विधि "पब्लिक वेड अटैक (स्ट्रिंग टारगेट)" को बरकरार रखूंगा और इसे "this.Attack (इस.वैप, टारगेट)" कहूंगा।
लुइज एंजेलो

और फिर कारखानों के साथ मिलकर, आप CreateSwordSamurai () जैसे तरीके प्राप्त कर सकते हैं! अच्छा उदाहरण है।
गीर्टेन

2
महान उदाहरण! इतना स्पष्ट ...
सर्ज वैन डेन ओवर

@ ल्यूज एंजेलो क्षमा करें, मुझे यकीन नहीं है कि मैंने आपकी टिप्पणी को समझ लिया है: "वास्तव में, मुझे लगता है कि आप IWeapon को हमला करने के तरीके के पैरामीटर के रूप में पास करना बेहतर होगा। जैसे .."। आपका मतलब है समुराई वर्ग में हमला करने का तरीका?
पैप

3

मैं इसे बहुत प्राथमिक बनाने के लिए यथासंभव प्रयास करूंगा। इस तरह, आप अवधारणा पर निर्माण कर सकते हैं और अपने स्वयं के जटिल समाधान या विचार बना सकते हैं।

अब कल्पना कीजिए कि हमारे पास जुबली नामक एक चर्च है, जिसकी शाखाएँ विश्वव्यापी हैं। हमारा उद्देश्य केवल प्रत्येक शाखा से एक आइटम प्राप्त करना है। यहां DI के साथ समाधान होगा;

1) एक इंटरफ़ेस बनाएं IJubilee:

public interface IJubilee
{
    string GetItem(string userInput);
}

2) एक क्लास जुबलीडे बनाएं जो एक कंस्ट्रक्टर के रूप में IJubilee इंटरफ़ेस ले और एक आइटम लौटाए:

public class JubileeDI
{
    readonly IJubilee jubilee;

    public JubileeDI(IJubilee jubilee)
    {
        this.jubilee = jubilee;
    }

    public string GetItem(string userInput)
    {
        return this.jubilee.GetItem(userInput);
    }
}

3) अब जुबली के तीन ब्रेक्स बनाएं जैसे जुबलीगेट, जुबलीहॉग, जुबलीकोव, जो सभी जरूरी है IJubilee इंटरफ़ेस। इसके मज़े के लिए, उनमें से एक को इसकी विधि को आभासी के रूप में लागू करें:

public class JubileeGT : IJubilee
{
    public virtual string GetItem(string userInput)
    {
        return string.Format("For JubileeGT, you entered {0}", userInput);
    }
}

public class JubileeHOG : IJubilee
{
    public string GetItem(string userInput)
    {
        return string.Format("For JubileeHOG, you entered {0}", userInput);
    }
}

public class JubileeCOV : IJubilee
{
    public string GetItem(string userInput)
    {
        return string.Format("For JubileCOV, you entered {0}", userInput);
    }
}

public class JubileeGTBranchA : JubileeGT
{
    public override string GetItem(string userInput)
    {
        return string.Format("For JubileeGT branch A, you entered {0}", userInput);
    }
}

4) यह बात है! अब हमें DI को कार्रवाई में देखते हैं:

        JubileeDI jCOV = new JubileeDI(new JubileeCOV());
        JubileeDI jHOG = new JubileeDI(new JubileeHOG());
        JubileeDI jGT = new JubileeDI(new JubileeGT());
        JubileeDI jGTA = new JubileeDI(new JubileeGTBranchA());

        var item = jCOV.GetItem("Give me some money!");
        var item2 = jHOG.GetItem("Give me a check!");
        var item3 = jGT.GetItem("I need to be fed!!!");
        var item4 = jGTA.GetItem("Thank you!");

कंटेनर क्लास के प्रत्येक उदाहरण के लिए, हमें उस वर्ग का एक नया उदाहरण पास करना होगा जिसकी हमें आवश्यकता है, जो ढीली युग्मन को सक्षम करता है।

आशा है कि यह अवधारणा संक्षेप में बताएगी।


2

मान लीजिए कि आपके पास एक वर्ग Aहै जिसका प्रत्येक उदाहरण दूसरे वर्ग के उदाहरण की आवश्यकता है B

class A
{
   B b;
}

निर्भरता इंजेक्शन का मतलब है कि संदर्भ Bउस ऑब्जेक्ट द्वारा सेट किया जाता है जो उदाहरण का प्रबंधन करता है A(जैसा कि वर्ग Aको Bसीधे संदर्भ को प्रबंधित करने से विरोध किया जाता है)।

कंस्ट्रक्टर इंजेक्शन का मतलब है कि कंस्ट्रक्टर के Bपैरामीटर के रूप में इसे पास किया जाता है Aऔर कंस्ट्रक्टर में सेट किया जाता है:

class A
{
    B b;

    A(B b)
    {
        this.b = b;
    }
}

एक संदर्भ के लिए सेट करने के लिए एक सेटर विधि (या एक संपत्ति) का उपयोग करना है B। इस स्थिति में, वह ऑब्जेक्ट जो किसी इंस्टेंस aको प्रबंधित करता है Aउसे पहले के कंस्ट्रक्टर को कॉल करना चाहिए Aऔर बाद में उपयोग किए जाने A.bसे पहले सदस्य चर सेट करने के लिए सेटर विधि को कॉल करना चाहिए a। अगर एक उदाहरण जब वस्तुओं, एक दूसरे को जैसे को चक्रीय संदर्भ होते हैं बाद इंजेक्शन विधि के लिए आवश्यक है bकी Bहै कि किसी स्थिति में सेट किया गया है aके Aलिए एक वापस संदर्भ है a

** EDIT **

टिप्पणी को संबोधित करने के लिए यहां कुछ और विवरण दिए गए हैं।

1. कक्षा ए बी उदाहरण का प्रबंधन करता है

class A
{
    B b;

    A()
    {
        b = new B();
    }
 }

2. बी कंस्ट्रक्टर में सेट किया गया है

class A
{
    B b;

    A(B b)
    {
        this.b = b;
    }
}

class M
{
    ...
    B b = new B();
    A a = new A(b);
}

3. बी उदाहरण सेटर विधि का उपयोग करके सेट किया गया है

class A
{
    B b;

    A()
    {
    }

    void setB(B b)
    {
        this.b = b;
    }
}

class M
{
    ...
    B b = new B();
    A a = new A();

    a.setB(b);
}

... के रूप में वर्ग ए सीधे बी के संदर्भ के प्रबंध होने का विरोध किया । इसका क्या मतलब है? आप इसे कोड में कैसे करेंगे? (मेरी अज्ञानता को क्षमा करें।)
TheSilverBullet

1
समुराई उदाहरण इतना बेहतर है। चलो सब चर के लिए पत्र का उपयोग करना बंद करें ...
स्टुअर्टडनेट

@stuartdotnet: मैं समुराई उदाहरण से बदतर होने के बारे में विवाद नहीं करता, लेकिन एक-अक्षर वाले चर का उपयोग क्यों करना बंद करूं? यदि चर का कोई विशेष अर्थ नहीं है, लेकिन सिर्फ प्लेसहोल्डर हैं, तो एकल-अक्षर चर बहुत अधिक कॉम्पैक्ट और बिंदु तक हैं। लंबे समय तक नाम बनाने के लिए itemAया objectAसिर्फ नाम का उपयोग करना हमेशा बेहतर नहीं होता है।
जियोर्जियो

1
तब आपने मेरी बात को याद किया है - गैर-
विवरणित

@stuartdotnet: मुझे नहीं लगता कि मैंने आपकी बात को याद किया है: आप दावा करते हैं कि वर्णनात्मक नाम हमेशा बेहतर होते हैं और कोड को हमेशा अधिक पठनीय और आत्म-व्याख्यात्मक बनाते हैं।
जियोर्जियो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.