मुझे निर्भरता इंजेक्शन मिलता है, लेकिन क्या कोई मुझे आईओसी कंटेनर की आवश्यकता को समझने में मदद कर सकता है?


15

मैं माफी माँगता हूँ अगर यह सवाल का एक और दोहराव लगता है, लेकिन हर बार जब मुझे इस विषय के बारे में एक लेख मिलता है, तो यह ज्यादातर डीआई के बारे में बात करता है। तो, मुझे DI मिलता है, लेकिन मैं एक IoC कंटेनर की आवश्यकता को समझने की कोशिश कर रहा हूं, जो हर किसी को मिल रहा है। क्या आईओसी कंटेनर की बात वास्तव में केवल निर्भरता के ठोस कार्यान्वयन को "ऑटो-रिज़ॉल्यूशन" करने के लिए है? हो सकता है कि मेरी कक्षाओं में कई निर्भरताएँ न हों और शायद इसीलिए मैं बड़ी बात नहीं देख रहा हूँ, लेकिन मैं यह सुनिश्चित करना चाहता हूँ कि मैं कंटेनर की उपयोगिता को ठीक से समझ रहा हूँ।

मैं आमतौर पर अपने व्यावसायिक तर्क को एक ऐसी कक्षा में तोड़ देता हूं जो कुछ इस तरह दिख सकती है:

public class SomeBusinessOperation
{
    private readonly IDataRepository _repository;

    public SomeBusinessOperation(IDataRespository repository = null)
    {
        _repository = repository ?? new ConcreteRepository();
    }

    public SomeType Run(SomeRequestType request)
    {
        // do work...
        var results = _repository.GetThings(request);

        return results;
    }
}

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

जहां तक ​​एक IoC कंटेनर की मेरी वर्तमान समझ है, सभी कंटेनर IDataRepository को हल करता है। लेकिन अगर यह सब ऐसा होता है, तो मैं इसमें एक टन का मूल्य नहीं देख रहा हूं क्योंकि मेरी परिचालन कक्षाएं पहले से ही एक कमबैक को परिभाषित करती हैं जब कोई योग्यता पारित नहीं हुई है। इसलिए केवल एक अन्य लाभ जो मैं सोच सकता हूं वह यह है कि अगर मेरे पास कई ऑपरेशन हैं जैसे यह उसी फ़ॉलबैक रेपो का उपयोग करता है, मैं उस रेपो को एक स्थान पर बदल सकता हूं जो रजिस्ट्री / फैक्टरी / कंटेनर है। और यह बहुत अच्छा है, लेकिन क्या ऐसा है?


1
अक्सर निर्भरता का डिफ़ॉल्ट फ़ॉलबैक संस्करण होने का वास्तव में कोई मतलब नहीं होता है।
बेन आरोनसन

आपका क्या मतलब है? "फॉलबैक" एक ठोस वर्ग है जो इकाई परीक्षणों को छोड़कर हर समय बहुत अधिक उपयोग किया जाता है। वास्तव में, यह कंटेनर में पंजीकृत एक ही वर्ग होगा।
सिनास्टेटिक

हां, लेकिन कंटेनर के साथ: (1) कंटेनर में अन्य सभी वस्तुओं को एक ही उदाहरण मिलता है ConcreteRepositoryऔर (2) आप अतिरिक्त निर्भरता की आपूर्ति कर सकते हैं ( उदाहरण के लिए ConcreteRepositoryएक डेटाबेस कनेक्शन सामान्य होगा)।
जूल्स

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

मैं एक टीशर्ट बनाने जा रहा हूं जिसमें लिखा है "फ़ंक्शन पैरामीटर - मूल निर्भरता इंजेक्शन!"
ग्राहम

जवाबों:


2

IoC कंटेनर उस मामले के बारे में नहीं है जहां आपके पास एक निर्भरता है। यह उस मामले के बारे में है जहां आपके पास 3 निर्भरताएं हैं और उनके पास कई निर्भरताएं हैं जिनकी निर्भरताएं आदि हैं।

यह आपको एक निर्भरता और जीवन चक्र प्रबंधन पर निर्भरता के संकल्प को केंद्रीकृत करने में भी मदद करता है।


10

कई कारण हैं कि आप आईओसी कंटेनर का उपयोग क्यों करना चाहते हैं।

अपरिचित डीएलएस

एक अनिर्दिष्ट डीएल से एक ठोस वर्ग को हल करने के लिए आप एक IoC कंटेनर का उपयोग कर सकते हैं। इसका मतलब है कि आप पूरी तरह से अमूर्त पर निर्भरता ले सकते हैं - अर्थात इंटरफ़ेस।

के उपयोग से बचें new

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

सार के खिलाफ लिखें

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

भंगुर कोड से बचें

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

लाइफटाइम मैनेजमेंट और अनवांटेड रिसौस क्लीनअप

अंतिम कारण जो मैं उल्लेख करूंगा वह वस्तु जीवनकाल का प्रबंधन है। IoC कंटेनर अक्सर किसी वस्तु के जीवनकाल को निर्दिष्ट करने की क्षमता प्रदान करते हैं। यह एक IoC कंटेनर में किसी ऑब्जेक्ट के जीवनकाल को निर्दिष्ट करने के बजाय कोड में मैन्युअल रूप से प्रबंधित करने की कोशिश करने के लिए बहुत अधिक समझ में आता है। मैनुअल आजीवन प्रबंधन बहुत मुश्किल हो सकता है। यह उन वस्तुओं से निपटने के लिए उपयोगी हो सकता है जिन्हें निपटान की आवश्यकता होती है। मैन्युअल रूप से अपनी वस्तुओं के निपटान का प्रबंधन करने के बजाय, कुछ IoC कंटेनर आपके लिए निपटान का प्रबंधन करेंगे, जो मेमोरी लीक को रोकने और आपके कोडबेस को सरल बनाने में मदद कर सकते हैं।

आपके द्वारा प्रदान किए गए नमूना कोड के साथ समस्या यह है कि आप जिस वर्ग को लिख रहे हैं, उसके पास कंकरीट रिपॉजिटरी वर्ग पर एक ठोस निर्भरता है। एक IoC कंटेनर उस निर्भरता को हटा देगा।


22
ये IoC कंटेनरों के फायदे नहीं हैं, वे निर्भरता इंजेक्शन के फायदे हैं, जो गरीब आदमी के DI के साथ आसानी से किया जा सकता है
बेन आरोनसन

IoC कंटेनर के बिना अच्छा DI कोड लिखना वास्तव में मुश्किल हो सकता है। हां, फायदे में कुछ ओवरलैप है, लेकिन ये सभी फायदे एक आईओसी कंटेनर के साथ सबसे अच्छा फायदा उठाते हैं।
स्टीफन

खैर, मेरी टिप्पणी के बाद आपके द्वारा जोड़े गए अंतिम दो कारण कंटेनर-विशिष्ट हैं और मेरी राय में दोनों बहुत मजबूत तर्क हैं
बेन आरोनसन

"नए के उपयोग से बचें" - स्थैतिक कोड विश्लेषण में भी बाधा उत्पन्न करता है, इसलिए आपको कुछ इस तरह का उपयोग करना शुरू करना होगा: hmemcpy.github.io/AgentMulder । इस अनुच्छेद में आपके द्वारा वर्णित अन्य लाभ डीआई के साथ हैं न कि आईओसी के साथ। साथ ही आपकी कक्षाएं अभी भी युग्मित होंगी यदि आप नए का उपयोग करने से बचते हैं लेकिन मापदंडों के लिए इंटरफेस के बजाय कंक्रीट प्रकार का उपयोग करेंगे।
डेन

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

2

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

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

उदाहरण के लिए इन सिद्धांतों का संयोजन (कम गुणवत्ता कोड के लिए खेद है, मैंने C # के बजाय कुछ तदर्थ भाषा का उपयोग किया, क्योंकि मुझे नहीं पता है कि):

  1. न एसआरपी, न आईओसी

    class SomeHighLevelService
    {
        public doFooBar(){
            Crap crap = doFoo();
            doBar(crap);
        }
    
        public Crap doFoo(){
            //...
            return crap;
        }
    
        public doBar(Crap crap){
            //...
        }
    }
    
    SomeHighLevelService service = new SomeHighLevelService();
    service.doFooBar();
  2. SRP के करीब, कोई IoC नहीं

    class SomeHighLevelService
    {
        public SomeHighLevelService(){
            Foo foo = new Foo();
            Bar bar = new Bar();
        }
    
        public doFooBar(){
            Crap crap = foo.doFoo();
            bar.doBar(crap);
        }
    }
    
    class Foo {
        public Crap doFoo(){
            //...
            return crap;
        }
    }
    
    class Bar {
        public doBar(Crap crap){
            //...
        }
    }
    
    SomeHighLevelService service = new SomeHighLevelService();
    service.doFooBar();
  3. हां एसआरपी, आईओसी नहीं

    class HighLevelServiceProvider {
        public SomeHighLevelService getSomeHighLevelService(){
            SomeHighLevelService service = new SomeHighLevelService();
            service.setFoo(this.getFoo());
            service.getBar(this.getBar());
            return service;
        }
    
        private Foo getFoo(){
            return new Foo();
        }
    
        private Bar getBar(){
            return new Bar();
        }
    }
    
    class SomeHighLevelService
    {           
        public setFoo(Foo foo){
            this.foo = foo;
        }
    
        public setBar(Bar bar){
            this.bar = bar;
        }
    
        public doFooBar(){
            Crap crap = foo.doFoo();
            bar.doBar(crap);
        }
    
    }
    
    class Foo {
        public Crap doFoo(){
            //...
            return crap;
        }
    }
    
    class Bar {
        public doBar(Crap crap){
            //...
        }
    }
    
    HighLevelServiceProvider provider = new HighLevelServiceProvider();
    SomeHighLevelService service = provider.getSomeHighLevelService();
    service.doFooBar();
  4. हाँ SRP, हाँ IoC

    interface HighLevelServiceProvider {
        SomeHighLevelService getSomeHighLevelService();
    }
    
    interface SomeHighLevelService {
        doFooBar();
    }
    
    interface Foo {
        Crap doFoo();
    }
    
    interface Bar {
        doBar(Crap crap);
    }
    
    
    class ConcreteHighLevelServiceContainer implements HighLevelServiceProvider {
        public SomeHighLevelService getSomeHighLevelService(){
            SomeHighLevelService service = new ConcreteHighLevelService();
            service.setFoo(this.getFoo());
            service.getBar(this.getBar());
            return service;
        }
    
        private Foo getFoo(){
            return new ConcreteFoo();
        }
    
        private Bar getBar(){
            return new ConcreteBar();
        }
    }
    
    class ConcreteHighLevelService implements SomeHighLevelService
    {           
        public setFoo(Foo foo){
            this.foo = foo;
        }
    
        public setBar(Bar bar){
            this.bar = bar;
        }
    
        public doFooBar(){
            Crap crap = foo.doFoo();
            bar.doBar(crap);
        }
    
    }
    
    class ConcreteFoo implements Foo {
        public Crap doFoo(){
            //...
            return crap;
        }
    }
    
    class ConcreteBar implements Bar {
        public doBar(Crap crap){
            //...
        }
    }
    
    
    HighLevelServiceProvider provider = new ConcreteHighLevelServiceContainer();
    SomeHighLevelService service = provider.getSomeHighLevelService();
    service.doFooBar();

इसलिए हमने एक कोड रखा, जिसमें आप प्रत्येक ठोस कार्यान्वयन को दूसरे के साथ बदल सकते हैं जो उसी इंटरफ़ेस inc को लागू करता है। इसलिए यह अच्छा है क्योंकि भाग लेने वाले वर्गों को एक-दूसरे से अलग कर दिया जाता है, वे केवल इंटरफेस को जानते हैं। एक और लाभ जो कि तात्कालिकता का कोड पुन: प्रयोज्य है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.