निर्भरता इंजेक्शन समझना


109

मैं निर्भरता इंजेक्शन (DI) के बारे में पढ़ रहा हूं । मेरे लिए, यह करने के लिए एक बहुत ही जटिल बात है, जैसा कि मैं पढ़ रहा था यह नियंत्रण के उलटा (IoC) का संदर्भ दे रहा था और साथ ही मुझे लगा कि मैं एक यात्रा के लिए जा रहा था।

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

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

मेरी समझ गैर-डीआई है (छद्म कोड का उपयोग करके):

public void Start()
{
    MyClass class = new MyClass();
}

...

public MyClass()
{
    this.MyInterface = new MyInterface(); 
}

और DI होगा

public void Start()
{
    MyInterface myInterface = new MyInterface();
    MyClass class = new MyClass(myInterface);
}

...

public MyClass(MyInterface myInterface)
{
    this.MyInterface = myInterface; 
}

के रूप में कुछ यकीन है कि मैं यहाँ एक अव्यवस्था में हूँ मैं कुछ प्रकाश बहा सकता है।


5
MyInterface और MyClass के 5 होने की कोशिश करें और एक निर्भरता श्रृंखला बनाने वाले कई वर्ग हैं। सब कुछ सेट करने के लिए बट में दर्द हो जाता है।
व्यंग्यात्मक

159
" मेरे लिए, यह सिर्फ एक तर्क दे रहा है। मुझे इस बात को गलत समझना चाहिए था? " नहीं। आपको यह मिला। यह "निर्भरता इंजेक्शन" है। अब देखिए कि सरल अवधारणाओं के लिए आप किस अन्य पागल शब्द के साथ आ सकते हैं, यह मजेदार है!
एरिक लिपर्ट

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

16
@EricLippert: सही करते समय, मुझे लगता है कि यह थोड़ा कम करने वाला है। Parameters-as-DI आपके औसत अनिवार्य / OO प्रोग्रामर के लिए तुरंत सीधी अवधारणा नहीं है, जो डेटा पास करने के लिए उपयोग किया जाता है। DI यहाँ आपको व्यवहार को पास करने दे रहा है, जिसमें औसत दर्जे के प्रोग्रामर की तुलना में अधिक लचीले विश्वदृष्टि की आवश्यकता होती है।
फॉशी

14
@ घोषी: आप एक अच्छा बिंदु बनाते हैं, लेकिन आपने इस पर भी अपनी उंगली उठाई है कि मुझे संदेह क्यों है कि "निर्भरता इंजेक्शन" पहली जगह में एक अच्छा विचार है। यदि मैं एक वर्ग लिखता हूं जो किसी अन्य वर्ग के व्यवहार पर उसकी शुद्धता और प्रदर्शन के लिए निर्भर करता है , तो आखिरी बात जो मैं करना चाहता हूं वह वर्ग के उपयोगकर्ता को निर्भरता के सही निर्माण और विन्यास के लिए जिम्मेदार बनाता है! यही मेरा काम है। हर बार जब आप एक उपभोक्ता को एक निर्भरता इंजेक्ट करते हैं, तो आप एक ऐसा बिंदु बनाते हैं जहाँ उपभोक्ता गलत कर सकता है।
एरिक लिपर्ट

जवाबों:


106

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

एक और कारण परीक्षण के लिए है।
यदि आपके पास फ़ाइल रीडर इंटरफ़ेस पर निर्भरता है और आप इस निर्भरता को एक निर्माता के माध्यम से इंजेक्ट करते हैं, तो कहो, ConsumerClass, इसका मतलब है कि परीक्षण के दौरान, आप फ़ाइल रीडर के इन-मेमोरी कार्यान्वयन को ConsumerClass में पास कर सकते हैं, आवश्यकता से बचते हुए परीक्षण के दौरान I / O करते हैं।


13
यह बहुत अच्छा है, अच्छी तरह से समझाया गया है। कृपया एक काल्पनिक +1 स्वीकार करें क्योंकि मेरा प्रतिनिधि इसे अभी तक अनुमति नहीं देगा!
MyDaftQuestions

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

1
@MattGibson अच्छी बात है।
स्टीफन बिलिएट

2
परीक्षण के लिए +1, अच्छी तरह से संरचित DI, आपके द्वारा परीक्षण किए जा रहे वर्ग के भीतर परीक्षण और यूनिट परीक्षण को तेज करने में मदद करेगा।
उमूर कोंटासी

52

DI को कैसे कार्यान्वित किया जा सकता है यह प्रयुक्त भाषा पर बहुत निर्भर करता है।

यहाँ एक गैर-डीआई उदाहरण दिया गया है:

class Foo {
    private Bar bar;
    private Qux qux;

    public Foo() {
        bar = new Bar();
        qux = new Qux();
    }
}

यह बेकार है, उदाहरण के लिए जब एक परीक्षण के लिए मैं एक नकली वस्तु का उपयोग करना चाहता हूं bar। इसलिए हम इसे और अधिक लचीला बना सकते हैं और निर्माणकर्ता के माध्यम से पारित होने की अनुमति दे सकते हैं:

class Foo {
    private Bar bar;
    private Qux qux;

    public Foo(Bar bar, Qux qux) {
        this.bar = bar;
        this.qux = qux;
    }
}

// in production:
new Foo(new Bar(), new Qux());
// in test:
new Foo(new BarMock(), new Qux());

यह पहले से ही निर्भरता इंजेक्शन का सबसे सरल रूप है। लेकिन यह अभी भी बेकार है क्योंकि सब कुछ मैन्युअल रूप से किया जाना है (इसलिए भी, क्योंकि कॉलर हमारी आंतरिक वस्तुओं का संदर्भ रख सकता है और इस तरह हमारे राज्य को अमान्य कर सकता है)।

हम कारखानों का उपयोग करके अधिक अमूर्तता का परिचय दे सकते हैं:

  • एक विकल्प Fooएक सार कारखाने द्वारा उत्पन्न किया जाना है

    interface FooFactory {
        public Foo makeFoo();
    }
    
    class ProductionFooFactory implements FooFactory {
        public Foo makeFoo() { return new Foo(new Bar(), new Baz()) }
    }
    
    class TestFooFactory implements FooFactory {
        public Foo makeFoo() { return new Foo(new BarMock(), new Baz()) }
    }
    
    FooFactory fac = ...; // depends on test or production
    Foo foo = fac.makeFoo();
    
  • एक अन्य विकल्प यह है कि निर्माणकर्ता को एक कारखाना दिया जाए:

    interface DependencyManager {
        public Bar makeBar();
        public Qux makeQux();
    }
    class ProductionDM implements DependencyManager {
        public Bar makeBar() { return new Bar() }
        public Qux makeQux() { return new Qux() }
    }
    class TestDM implements DependencyManager {
        public Bar makeBar() { return new BarMock() }
        public Qux makeQux() { return new Qux() }
    }
    
    class Foo {
        private Bar bar;
        private Qux qux;
    
        public Foo(DependencyManager dm) {
            bar = dm.makeBar();
            qux = dm.makeQux();
        }
    }
    

इसके साथ शेष समस्याएं यह हैं कि हमें DependencyManagerप्रत्येक कॉन्फ़िगरेशन के लिए एक नया उपवर्ग लिखने की आवश्यकता है , और यह कि निर्भरता की संख्या जो प्रबंधित की जा सकती है वह काफी प्रतिबंधित है (प्रत्येक नई निर्भरता को इंटरफ़ेस में एक नई विधि की आवश्यकता है)।

प्रतिबिंब और गतिशील वर्ग लोडिंग जैसी सुविधाओं के साथ हम इसे दरकिनार कर सकते हैं। लेकिन यह बहुत इस्तेमाल की जाने वाली भाषा पर निर्भर करता है। पर्ल में, कक्षाओं को उनके नाम से संदर्भित किया जा सकता है, और मैं बस कर सकता था

package Foo {
    use signatures;

    sub new($class, $dm) {
        return bless {
            bar => $dm->{bar}->new,
            qux => $dm->{qux}->new,
        } => $class;
    }
}

my $prod = { bar => 'My::Bar', qux => 'My::Qux' };
my $test = { bar => 'BarMock', qux => 'QuxMock' };
$test->{bar} = 'OtherBarMock';  # change conf at runtime

my $foo = Foo->new(rand > 0.5 ? $prod : $test);

जावा जैसी भाषाओं में, मैं निर्भरता प्रबंधक के समान व्यवहार कर सकता है Map<Class, Object>:

Bar bar = dm.make(Bar.class);

किस वास्तविक वर्ग Bar.classको हल किया जाता है, रनटाइम पर कॉन्फ़िगर किया जा सकता है, उदाहरण के Map<Class, Class>लिए कार्यान्वयन के लिए एक मानचित्र मानचित्र को बनाए रखने के द्वारा ।

Map<Class, Class> dependencies = ...;

public <T> T make(Class<T> c) throws ... {
    // plus a lot more error checking...
    return dependencies.get(c).newInstance();
}

कंस्ट्रक्टर लिखने में अभी भी एक मैनुअल तत्व शामिल है। लेकिन हम एनोटेशन के जरिए DI को चलाकर कंस्ट्रक्टर को पूरी तरह से अनावश्यक बना सकते हैं:

class Foo {
    @Inject(Bar.class)
    private Bar bar;

    @Inject(Qux.class)
    private Qux qux;

    ...
}

dm.make(Foo.class);  // takes care of initializing "bar" and "qux"

यहां एक छोटे (और बहुत प्रतिबंधित) DI ढांचे का एक उदाहरण कार्यान्वयन है: http://ideone.com/b2ubuF , हालांकि यह कार्यान्वयन अपरिवर्तनीय वस्तुओं के लिए पूरी तरह से अनुपयोगी है (यह भोली कार्यान्वयन कंस्ट्रक्टर के लिए कोई पैरामीटर नहीं ले सकता है)।


7
यह महान उदाहरणों के साथ सुपर है, हालांकि इसे पढ़ने के लिए मुझे यह सब पचाने में कुछ समय लगने वाला है, लेकिन इतना समय लेने के लिए धन्यवाद।
MyDaftQuestions

33
यह मजेदार है कि प्रत्येक अगला सरलीकरण कैसे अधिक जटिल है
क्रॉमस्टर

48

स्टैक ओवरफ्लो पर हमारे दोस्तों के पास इसका अच्छा जवाब है । मेरा पसंदीदा उद्धरण सहित दूसरा उत्तर है:

"निर्भरता इंजेक्शन" 5-प्रतिशत अवधारणा के लिए 25-डॉलर का शब्द है। (...) निर्भरता इंजेक्शन का अर्थ है किसी वस्तु को उसके उदाहरण चर देना। (...)।

से जेम्स शोर के ब्लॉग । बेशक, इसके शीर्ष पर अधिक जटिल संस्करण / पैटर्न हैं, लेकिन यह मूल रूप से समझने के लिए पर्याप्त है कि क्या चल रहा है। एक वस्तु के बजाय अपने स्वयं के उदाहरण चर बनाने के लिए, वे बाहर से पारित किए जाते हैं।


10
मैंने इसे पढ़ा था ... और अब तक, इसका कोई मतलब नहीं था ... अब, यह समझ में आता है। निर्भरता वास्तव में इतनी बड़ी अवधारणा नहीं है जिसे समझना (चाहे वह कितना भी शक्तिशाली क्यों न हो) लेकिन इसका एक बड़ा नाम है और इसके साथ बहुत अधिक इंटरनेट शोर है!
MyDaftQuestions

18

मान लें कि आप अपने रहने वाले कमरे में आंतरिक डिजाइन कर रहे हैं: आप अपने छत पर एक फैंसी झूमर स्थापित करते हैं और उत्तम दर्जे के मिलान वाले दीपक में प्लग करते हैं। एक साल बाद आपकी प्यारी पत्नी ने फैसला किया कि वह कमरे को थोड़ा कम औपचारिक बनाएगी। कौन सा प्रकाश स्थिरता बदलने के लिए आसान होने जा रहा है?

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

लेकिन एक बड़े और जटिल अनुप्रयोग के लिए, डीआई दीर्घकालिक रखरखाव के लिए अपरिहार्य है । यह आपको अपने कोड (उदाहरण के लिए डेटाबेस बैकएंड) से पूरे मॉड्यूल को "अनप्लग" करने की अनुमति देता है, और उन्हें अलग-अलग मॉड्यूल के साथ एक्सचेंज करता है जो एक ही चीज़ को पूरा करते हैं लेकिन इसे पूरी तरह से अलग तरीके से करते हैं (उदाहरण के लिए क्लाउड स्टोरेज सिस्टम)।

बीटीडब्ल्यू, मार्क सेमैन द्वारा .NET में डिपेंडेंसी इंजेक्शन की सिफारिश के बिना DI की चर्चा अधूरी होगी । यदि आप .NET से परिचित हैं और आप कभी भी बड़े पैमाने पर SW विकास में शामिल होना चाहते हैं, तो यह एक आवश्यक रीड है। वह अवधारणा को मुझसे बेहतर तरीके से समझाता है।

मुझे आपको DI की एक अंतिम आवश्यक विशेषता के साथ छोड़ना चाहिए जो आपके कोड उदाहरण को अनदेखा करता है। DI आपको लचीलेपन की विशाल क्षमता का उपयोग करने की अनुमति देता है जो कि " प्रोग्राम टू इंटरफेसेस " में संलग्न है । अपने उदाहरण को थोड़ा संशोधित करने के लिए:

public void Main()
{
    ILightFixture fixture = new ClassyChandelier();
    MyRoom room = new MyRoom (fixture);
}
...
public MyRoom(ILightFixture fixture)
{
    this.MyLightFixture = fixture ; 
}

लेकिन अब, क्योंकि MyRoomILightFixture इंटरफ़ेस के लिए डिज़ाइन किया गया है , मैं आसानी से अगले वर्ष में जा सकता हूं और मुख्य फ़ंक्शन में एक पंक्ति को बदल सकता हूं ("इंजेक्शन" एक अलग "निर्भरता"), और मैं तुरंत MyRoom में नई कार्यक्षमता प्राप्त कर रहा हूं (बिना होने के लिए) MyRoom को फिर से बनाएँ या फिर से तैयार करें, यदि यह एक अलग लाइब्रेरी में होता है। यह मानता है, कि आपके सभी ILightFixture कार्यान्वयन Liskov सबस्टिट्यूट को ध्यान में रखते हुए तैयार किए गए हैं)। बस, एक साधारण बदलाव के साथ:

public void Main()
{
    ILightFixture fixture = new MuchLessFormalLightFixture();
    MyRoom room = new MyRoom (fixture);
}

इसके अलावा, मैं अब यूनिट टेस्ट MyRoom(आप इकाई परीक्षण, सही?) कर रहे हैं और "मॉक" प्रकाश स्थिरता का उपयोग कर सकते हैं , जो मुझे MyRoomपूरी तरह से स्वतंत्र परीक्षण करने की अनुमति देता हैClassyChandelier.

निश्चित रूप से कई और फायदे हैं, लेकिन ये वही हैं जिन्होंने इस विचार को मुझे बेच दिया।


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

2
मुझे उस पुस्तक में भी दिलचस्पी है जिसे आपने संदर्भित किया है, लेकिन मुझे यह पता चलता है कि इस विषय पर 584 पृष्ठ की पुस्तक है।
स्टीव

4

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

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

मैं इस बात का उल्लेख करता हूं क्योंकि आप निर्भरता इंजेक्शन के "लापता बिंदु" के बारे में बात करते हैं, और यह इस बात का बहुत हिस्सा है कि लोग इसे क्यों करना पसंद करते हैं। इसका मतलब सिर्फ एक पैरामीटर पास करना हो सकता है, लेकिन क्या आप ऐसा करते हैं, यह महत्वपूर्ण हो सकता है।

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

public void Start()
{
    MySubSubInterfaceA mySubSubInterfaceA = new mySubSubInterfaceA();
    MySubSubInterfaceB mySubSubInterfaceB = new mySubSubInterfaceB();     
    MySubInterface mySubInterface = new MySubInterface(mySubSubInterfaceA,mySubSubInterfaceB);
    MyInterface myInterface = new MyInterface(MySubInterface);
    MyClass class = new MyClass(myInterface);
}

लेकिन इस तरह के एक और 400 लाइनों के साथ riveting कोड। यदि आप कल्पना करते हैं कि समय के साथ DI कंटेनरों की अपील अधिक स्पष्ट हो जाती है।

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

तो, निश्चित रूप से, निर्भरता इंजेक्शन बस एक पैरामीटर से गुजर रहा है, लेकिन वास्तव में जब लोग कहते हैं कि निर्भरता इंजेक्शन का अर्थ है "अपनी वस्तु के लिए एक पैरामीटर पास करना बनाम अपनी वस्तु को तुरंत कुछ होने का विकल्प", और कमियों के सभी लाभों से निपटना इस तरह के एक दृष्टिकोण, संभवतः डीआई कंटेनर की मदद से।


यह बहुत उप और इंटरफेस है! क्या आप एक वर्ग के बजाय एक इंटरफ़ेस को नया करने का मतलब है जो इंटरफ़ेस को लागू करता है? गलत लगता है।
JBRWilkinson

@JBRWilkinson मेरा मतलब है कि एक वर्ग जो एक इंटरफ़ेस को लागू करता है। मुझे वह स्पष्ट करना चाहिए। हालाँकि, मुद्दा यह है कि एक बड़े ऐप में आश्रितों के साथ कक्षाएं होंगी जो बदले में निर्भरताएं हैं जो बदले में निर्भरताएं हैं ... इसे मुख्य विधि में मैन्युअल रूप से स्थापित करना बहुत सारे कंस्ट्रक्टर इंजेक्शन करने का परिणाम है।
Psr

4

वर्ग स्तर पर, यह आसान है।

'डिपेंडेंसी इंजेक्शन' बस इस सवाल का जवाब देता है कि "मैं अपने सहयोगियों को कैसे ढूंढूंगा" के साथ "वे आपको धक्का देते हैं - आपको खुद जाने और उन्हें पाने की ज़रूरत नहीं है"। (यह समान है - लेकिन समान नहीं है - 'उलटा नियंत्रण' जहां सवाल "मैं अपने इनपुट पर अपना ऑर्डर कैसे करूंगा?" का एक समान उत्तर है)।

केवल लाभ यह है कि अपने सहयोगियों होने आप पर धक्का दे दिया है कि एक वस्तु ग्राफ जो सूट अपने वर्तमान की जरूरत रचना के लिए अपने वर्ग का उपयोग करने के लिए ग्राहक कोड के लिए सक्षम बनाता है ... आप मनमाने ढंग से नहीं किया है निजी तौर पर निर्णय लेने से से आकार और ग्राफ की अस्थिरता पूर्व निर्धारित आपके सहयोगियों के ठोस प्रकार और जीवन-चक्र।

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

यह ध्यान देने योग्य है कि, अगर आप अपने खुद के सहयोगियों instantiating से बचने के है, तो अपने वर्ग चाहिए लायक है इसलिए (यह दूसरा विकल्प अक्सर अनदेखी की है जिस तरह से अपने सहयोगियों एक निर्माता, एक संपत्ति है, या एक विधि-तर्क से मिलता है ... यह करता है हमेशा एक वर्ग 'सहयोगियों के लिए अपनी' राज्य 'का हिस्सा बनने के लिए कोई मतलब नहीं)।

और यह एक अच्छी बात है।

आवेदन स्तर पर ...

चीजों के प्रति-वर्गीय दृष्टिकोण के लिए बहुत कुछ। मान लें कि आपके पास कक्षाओं का एक समूह है, जो "अपने स्वयं के सहयोगियों को तत्काल न करें" नियम का पालन करते हैं, और उनसे एक आवेदन करना चाहते हैं। सबसे आसान काम यह है कि आप जिस वस्तु का ग्राफ चाहते हैं, उसकी रचना करें और उस पर कुछ इनपुट फेंकें, अच्छे पुराने कोड का उपयोग करें । (हां, आपके ग्राफ़ की कुछ वस्तुएं स्वयं ऑब्जेक्ट-फ़ैक्टरी होंगी, जो ग्राफ़ में अन्य लंबे समय तक जीवित ऑब्जेक्ट्स के सहयोगी के रूप में पारित हो चुकी हैं, सेवा के लिए तैयार हैं ... आप प्रत्येक ऑब्जेक्ट को पूर्व-निर्माण नहीं कर सकते हैं! )।

... आपके 'लचीलेपन' को आपके ऐप के ऑब्जेक्ट-ग्राफ़ को कॉन्फ़िगर करने की आवश्यकता है ...

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

... एक महत्वपूर्ण डिजाइन बल हो सकता है।

उस प्रकार की सबसे चरम परिस्थिति में, आप एक बहुत ही सामान्य दृष्टिकोण अपनाने के लिए चुनाव कर सकते हैं, और अंतिम उपयोगकर्ताओं को उनके चयन के ऑब्जेक्ट-ग्राफ को 'वायरिंग' करने के लिए एक सामान्य तंत्र दे सकते हैं और यहां तक ​​कि उन्हें इंटरफेस के ठोस अहसास प्रदान करने की अनुमति भी दे सकते हैं । क्रम! (आपका दस्तावेज़ीकरण एक शानदार गहना है, आपके उपयोगकर्ता बहुत स्मार्ट हैं, कम से कम आपके एप्लिकेशन के ऑब्जेक्ट ग्राफ़ की मोटे रूपरेखा से परिचित हैं, लेकिन एक संकलक काम करने के लिए ऐसा नहीं होता है)। यह परिदृश्य सैद्धांतिक रूप से कुछ 'उद्यम' स्थितियों में हो सकता है।

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

आप बेचारे सोद!

चूँकि आपने वह सब लिखने की कल्पना नहीं की, जो आप (लेकिन गंभीरता से, अपनी भाषा के लिए एक बंधन बाँधने की जाँच करें), आप किसी तरह के DI ढांचे का उपयोग कर रहे हैं।

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

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

Bootnote

किसी भी बिंदु पर आप कभी भी Google Guice का उपयोग नहीं कर रहे हैं, जो आपको कोड लिखने के साथ कोड-ऑब्जेक्ट ... को लिखने के कार्य के साथ कोडन करने का एक तरीका देता है । अरे!


0

बहुत सारे लोगों ने यहां कहा कि डीआई एक उदाहरण चर की शुरूआत को बाहर करने का एक तंत्र है।

स्पष्ट और सरल उदाहरणों के लिए आपको वास्तव में "निर्भरता इंजेक्शन" की आवश्यकता नहीं है। जैसा कि आप प्रश्न में उल्लेख किया गया है, आप कंस्ट्रक्टर को पास करने वाले एक साधारण पैरामीटर द्वारा कर सकते हैं।

हालाँकि, मुझे लगता है कि जब आप एप्लिकेशन-स्तरीय संसाधनों के बारे में बात करते हैं, तो एक समर्पित "निर्भरता इंजेक्शन" तंत्र उपयोगी होता है, जहां कॉलर और कैली दोनों इन संसाधनों के बारे में कुछ भी नहीं जानते हैं (और जानना नहीं चाहते हैं!)।

उदाहरण के लिए: डेटाबेस कनेक्शन, सुरक्षा संदर्भ, लॉगिंग सुविधा, कॉन्फ़िगरेशन फ़ाइल आदि।

इसके अलावा, सामान्य तौर पर हर सिंग्लटन डीआई के लिए एक अच्छा उम्मीदवार होता है। उनमें से आपके पास जितना अधिक है और उपयोग करें, उतने ही अधिक अवसरों के लिए आपको DI की आवश्यकता होगी।

इस प्रकार के संसाधनों के लिए यह बिल्कुल स्पष्ट है कि इन सभी को पैरामीटर सूचियों के माध्यम से स्थानांतरित करने का कोई मतलब नहीं है और इसलिए DI का आविष्कार किया गया था।

अंतिम नोट, आपको डीआई कंटेनर की भी आवश्यकता है, जो वास्तविक इंजेक्शन करेगा ... (फिर, कार्यान्वयन विवरण से कॉलर और कैली दोनों को जारी करने के लिए)।


-2

यदि आप अमूर्त संदर्भ प्रकार में पास होते हैं तो कॉलिंग कोड किसी भी ऑब्जेक्ट में पास हो सकता है जो अमूर्त प्रकार को लागू / लागू करता है। इसलिए भविष्य में ऑब्जेक्ट का उपयोग करने वाला वर्ग एक नई वस्तु का उपयोग कर सकता है जिसे कभी भी अपने कोड को संशोधित किए बिना बनाया गया है।


-4

यह एमन के जवाब के अलावा एक और विकल्प है

बिल्डरों का उपयोग करें:

कक्षा फू {
    निजी बार बार;
    निजी Qux qux;

    निजी फू () {
    }

    सार्वजनिक फू (बिल्डर बिल्डर) {
        this.bar = buildder.bar;
        this.qux = buildder.qux;
    }

    सार्वजनिक स्थिर वर्ग बिल्डर {
        निजी बार बार;
        निजी Qux qux;
        सार्वजनिक ब्यूडर सेटबार (बार बार) {
            this.bar = bar;
            इसे वापस करो;
        }
        सार्वजनिक बिल्डर सेटक्यूक्स (Qux qux) {
            this.qux = qux;
            इसे वापस करो;
        }
        सार्वजनिक फू बिल्ड () {
            नया फू लौटाओ (यह);
        }
    }
}

// उत्पादन में:
Foo foo = new Foo.Builder ()
    .setBar (नया बार ())
    .setQux (नया Qux ())
    .build ();

// परीक्षण में:
Foo testFoo = new Foo.Builder ()
    .setBar (नया BarMock ())
    .setQux (नया Qux ())
    .build ();

यह मैं निर्भरता के लिए उपयोग करता हूं। मैं किसी भी DI ढांचे का उपयोग नहीं करता। वे रास्ते में मिल जाते हैं।


4
यह एक साल पहले से अन्य उत्तरों में बहुत अधिक नहीं जोड़ता है, और कोई भी स्पष्टीकरण नहीं देता है कि कोई बिल्डर आश्रित इंजेक्शन को समझने में मदद क्यों कर सकता है।

@Snowman यह DI के स्थान पर ANOTHER विकल्प है। मुझे खेद है कि आप इसे इस तरह नहीं देख रहे हैं। डाउन वोट के लिए धन्यवाद।
user3155341

1
पूछने वाला यह समझना चाहता था कि क्या वास्तव में DI एक पैरामीटर को पार करने के रूप में सरल है, वह DI के लिए विकल्प नहीं पूछ रहा था।

1
ओपी के उदाहरण बहुत अच्छे हैं। आपके उदाहरण किसी ऐसी चीज के लिए अधिक जटिलता प्रदान करते हैं जो एक सरल विचार है। वे प्रश्न के मुद्दे का वर्णन नहीं करते हैं।
एडम जुकरमान

कंस्ट्रक्टर DI एक पैरामीटर पास कर रहा है। सिवाय आप एक ठोस क्लास ऑब्जेक्ट के बजाय एक इंटरफ़ेस ऑब्जेक्ट पास कर रहे हैं। यह एक ठोस कार्यान्वयन पर यह 'निर्भरता' है जिसे DI के माध्यम से हल किया गया है। कंस्ट्रक्टर को यह पता नहीं है कि यह टाइप किया जा रहा है, न ही इसकी परवाह है, यह सिर्फ जानता है कि यह एक प्रकार प्राप्त कर रहा है जो एक इंटरफ़ेस लागू करता है। मेरा सुझाव है कि PluralSight, यह एक महान शुरुआती डि / IOC पाठ्यक्रम है।
हार्डग्राफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.