निर्भरता इंजेक्शन पैटर्न का उपयोग करना कब उचित नहीं है?


124

स्वचालित परीक्षण सीखने (और प्यार) के बाद से मैंने लगभग हर परियोजना में निर्भरता इंजेक्शन पैटर्न का उपयोग करके खुद को पाया है। क्या स्वचालित परीक्षण के साथ काम करते समय हमेशा इस पैटर्न का उपयोग करना उचित है? क्या ऐसी कोई परिस्थितियां हैं जो आपको निर्भरता इंजेक्शन के उपयोग से बचना चाहिए?


1
संबंधित (शायद डुप्लिकेट नहीं) - stackoverflow.com/questions/2407540/…
Steve314

3
गोल्डन हैमर विरोधी पैटर्न की तरह थोड़ा सा लगता है। en.wikipedia.org/wiki/Anti-pattern
Cuga

जवाबों:


123

मूल रूप से, निर्भरता इंजेक्शन आपकी वस्तुओं की प्रकृति के बारे में कुछ (आमतौर पर लेकिन हमेशा मान्य नहीं) धारणा बनाता है। यदि वे गलत हैं, तो DI सबसे अच्छा समाधान नहीं हो सकता है:

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

    यह ठोस कार्यान्वयन में बदलाव के आधार पर निर्भर वस्तु को बदलने के लिए बंद कर देता है; ConsoleWriter पर निर्भर एक वर्ग को विशेष रूप से बदलने की आवश्यकता होगी यदि आउटपुट को इसके बजाय किसी फ़ाइल में जाने की आवश्यकता होती है, लेकिन यदि वर्ग केवल IWriter पर निर्भर करता है जो एक लिखें () विधि को उजागर करता है, तो हम वर्तमान में ConWWriter को एक FileWriter और हमारे साथ होने पर बदल सकते हैं आश्रित वर्ग को अंतर नहीं पता होगा (Liskhov प्रतिस्थापन सिद्धांत)।

    हालांकि, एक डिजाइन सभी प्रकार के परिवर्तन के लिए कभी भी बंद नहीं किया जा सकता है; यदि IWriter इंटरफ़ेस का डिज़ाइन स्वयं बदलता है, तो लिखने के लिए एक पैरामीटर जोड़ने के लिए (), एक अतिरिक्त कोड ऑब्जेक्ट (IWriter इंटरफ़ेस) को अब लागू किया जाना चाहिए, कार्यान्वयन ऑब्जेक्ट / विधि और इसके उपयोग (ओं) के शीर्ष पर। यदि वास्तविक इंटरफ़ेस में परिवर्तन उक्त इंटरफ़ेस के कार्यान्वयन के परिवर्तनों से अधिक होने की संभावना है, तो ढीली युग्मन (और DI-ing शिथिल-युग्मित निर्भरताएँ) इसकी तुलना में अधिक समस्याएँ पैदा कर सकती हैं।

  • दूसरा, और कोरोलरी, DI मानता है कि निर्भरता बनाने के लिए आश्रित वर्ग एक अच्छी जगह है । यह सिंगल रिस्पांसिबिलिटी प्रिंसिपल के पास जाता है; यदि आपके पास कोड है जो एक निर्भरता बनाता है और इसका उपयोग भी करता है, तो दो कारण हैं कि आश्रित वर्ग को एसआरपी का उल्लंघन करते हुए (उपयोग या कार्यान्वयन में बदलाव) बदलना पड़ सकता है।

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

  • अंत में, डीआई अपनी प्रकृति से सभी निर्भरता और उनके कार्यान्वयन के ज्ञान को केंद्रीकृत करता है । इससे उन संदर्भों की संख्या बढ़ जाती है जो असेंबली करते हैं जो इंजेक्शन होना चाहिए, और ज्यादातर मामलों में वास्तविक निर्भर वर्गों की विधानसभाओं द्वारा आवश्यक संदर्भों की संख्या को कम नहीं करता है।

    सोम्मेटिंग, कुछ लोग, आश्रितों, निर्भरता इंटरफेस और निर्भरता कार्यान्वयन का ज्ञान होना चाहिए ताकि "डॉट्स कनेक्ट करें" और उस निर्भरता को संतुष्ट कर सकें। DI उस सभी ज्ञान को एक उच्च स्तर पर रखने के लिए जाता है, या तो एक IoC कंटेनर में, या कोड में जो "मुख्य" ऑब्जेक्ट बनाता है जैसे कि मुख्य रूप या नियंत्रक जो कि निर्भरता को हाइड्रेट करना (या कारखाने के तरीके प्रदान करना) है। यह आपके ऐप के उच्च स्तरों पर बहुत आवश्यक रूप से युग्मित कोड और बहुत सारे असेंबली संदर्भ डाल सकता है, जिसे केवल वास्तविक आश्रित वर्गों से इसे "छिपाने" के लिए इस ज्ञान की आवश्यकता होती है (जो बहुत ही मूल दृष्टिकोण से है) इस ज्ञान को रखने के लिए सबसे अच्छी जगह; जहाँ इसका उपयोग किया जाता है)।

    यह आम तौर पर कोड में निचले संदर्भ से उक्त संदर्भों को भी नहीं हटाता है; एक आश्रित को अभी भी अपनी निर्भरता के लिए इंटरफ़ेस वाले पुस्तकालय का संदर्भ देना चाहिए, जो तीन स्थानों में से एक में है:

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

    यह सब, फिर से उन जगहों पर एक समस्या को हल करने के लिए जहां कोई नहीं हो सकता है।


1
SRP = एकल जिम्मेदारी सिद्धांत, किसी और के लिए सोच।
थियोडोर मर्डॉक

1
हाँ, और एलएसपी लिस्कोव प्रतिस्थापन सिद्धांत है; A पर निर्भरता को देखते हुए, निर्भरता को B से मिलने में सक्षम होना चाहिए जो A से किसी अन्य परिवर्तन के बिना प्राप्त होता है।
कीथ्स

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

क्या एक और धारणा "यदि एक निर्भरता बदलती है तो यह हर जगह बदलती है"? या फिर आपको वैसे भी सभी उपभोग वाली कक्षाओं को देखना होगा
रिचर्ड टिंगल

3
यह उत्तर निर्भरता बनाम उन्हें हार्डकोड करने के परीक्षण प्रभाव को संबोधित करने में विफल रहता है। यह भी स्पष्ट निर्भरता सिद्धांत (देखें deviq.com/explicit-dependencies-principle )
ssmith

30

निर्भरता-इंजेक्शन फ्रेमवर्क के बाहर, निर्भरता इंजेक्शन (कंस्ट्रक्टर इंजेक्शन या सेटर इंजेक्शन के माध्यम से) लगभग एक शून्य-राशि का खेल है: आप ऑब्जेक्ट ए के बीच युग्मन को कम करते हैं और यह निर्भरता बी है, लेकिन अब किसी भी ऑब्जेक्ट को ए की आवृत्ति की आवश्यकता है ऑब्जेक्ट बी का निर्माण भी करते हैं।

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

तो निर्भरता इंजेक्शन (एक ढांचे के बिना) उतना ही हानिकारक है जितना यह सहायक है।

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

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

यह मददगार हो सकता है, लेकिन आपको प्रत्येक निर्भरता के लिए अपने आप से निश्चित रूप से पूछना चाहिए, क्या परीक्षण लाभ लागत के लायक है, और क्या मैं वास्तव में परीक्षण करते समय इस निर्भरता का मजाक बनाना चाहता हूं?

जब एक निर्भरता-इंजेक्शन ढांचा जोड़ा जाता है, और निर्भरता का निर्माण ग्राहक कोड के लिए नहीं बल्कि फ्रेमवर्क के बजाय दिया जाता है, तो लागत / लाभ विश्लेषण बहुत बदल जाता है।

एक निर्भरता-इंजेक्शन ढांचे में, ट्रेडऑफ़ थोड़ा अलग हैं; एक निर्भरता को इंजेक्ट करके आप जो खो रहे हैं, वह आसानी से यह जानने की क्षमता है कि आप किस कार्यान्वयन पर भरोसा कर रहे हैं, और यह तय करने की ज़िम्मेदारी को शिफ्ट करने के लिए कि आप किस तरह की स्वचालित रिज़ॉल्यूशन प्रक्रिया पर भरोसा कर रहे हैं (जैसे कि अगर हमें @ Inject'ed फू की आवश्यकता है वहाँ कुछ होना चाहिए जो @Provides फू, और जिनकी इंजेक्शन निर्भरताएं उपलब्ध हैं), या कुछ उच्च-स्तरीय कॉन्फ़िगरेशन फ़ाइल में, जो निर्धारित करता है कि प्रत्येक संसाधन के लिए क्या प्रदाता का उपयोग किया जाना चाहिए, या दोनों के कुछ हाइब्रिड के लिए (उदाहरण के लिए, हो सकता है) निर्भरता के लिए एक स्वचालित रिज़ॉल्यूशन प्रक्रिया हो सकती है, जिसे ज़रूरत पड़ने पर, कॉन्फ़िगरेशन फ़ाइल का उपयोग करके, ओवरराइड किया जा सकता है)।

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

जबकि मुझे व्यक्तिगत रूप से DI चौखटे के साथ बहुत अच्छा अनुभव नहीं है, मेरी धारणा यह है कि वे लागत से अधिक लाभ प्रदान करते हैं जब डेटा या सेवा के सही प्रदाता को खोजने का सिरदर्द होता है जिसकी आपको सिरदर्द से अधिक लागत होती है। जब कुछ विफल हो जाता है, तो तुरंत स्थानीय रूप से न जाने क्या कोड खराब डेटा प्रदान करता है जो आपके कोड में बाद में विफलता का कारण बनता है।

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


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

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

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

3
निर्भरता इंजेक्शन केवल एक शून्य राशि के खेल में निर्भरता को आगे बढ़ाती है। आप अपने आश्रितों को उन स्थानों पर ले जाते हैं जहां वे पहले से मौजूद हैं: मुख्य परियोजना। आप यह सुनिश्चित करने के लिए भी कन्वेंशन-आधारित दृष्टिकोणों का उपयोग कर सकते हैं कि निर्भरता केवल रन टाइम पर हल की जाती है, उदाहरण के लिए यह निर्दिष्ट करके कि कौन सी कक्षाएं नाम स्थान या जो कुछ भी ठोस हैं। मेरा कहना है कि यह एक भोला जवाब है
स्प्रैग

2
अगर आप इसे लागू नहीं किया जाना चाहिए मामलों में इसे लागू अगर @Sprague निर्भरता इंजेक्शन एक थोड़ा नकारात्मक राशि के खेल में निर्भरता के आसपास चलता है। इस उत्तर का उद्देश्य लोगों को यह याद दिलाना है कि निर्भरता इंजेक्शन स्वाभाविक रूप से अच्छा नहीं है, यह एक डिजाइन पैटर्न है जो सही परिस्थितियों में अविश्वसनीय रूप से उपयोगी है, लेकिन सामान्य परिस्थितियों में एक अनुचित लागत (कम से कम प्रोग्रामिंग डोमेन में मैंने काम किया है) , मैं समझता हूं कि कुछ डोमेन में यह दूसरों की तुलना में अधिक उपयोगी है)। DI कभी-कभी अपने आप में एक चर्चा और अंत बन जाता है, जो बिंदु को याद करता है।
थियोडोर मर्डॉक

11
  1. यदि आप डेटाबेस इकाइयाँ बना रहे हैं, तो आपको कुछ कारखाने वर्ग चाहिए जो आप अपने नियंत्रक के बजाय इंजेक्ट करेंगे,

  2. यदि आपको किलों या लोंगो जैसी आदिम वस्तुओं को बनाने की आवश्यकता है। साथ ही आपको अधिकांश मानक पुस्तकालय वस्तुओं जैसे "दिनांक, हाथ" से "हाथ से" बनाना चाहिए।

  3. यदि आप कॉन्फ़िगरेशन स्ट्रिंग्स को इंजेक्ट करना चाहते हैं, तो यह संभव है कि कुछ कॉन्फ़िगरेशन ऑब्जेक्ट्स को इंजेक्ट करना बेहतर है (सामान्य तौर पर इसे सरल प्रकारों को सार्थक ऑब्जेक्ट्स में लपेटने की सिफारिश की जाती है: int temperatureInC सेल्सियसDegrees -> CelciusDeegree तापमान)

और निर्भरता इंजेक्शन विकल्प के रूप में सेवा लोकेटर का उपयोग न करें, यह एंटी-पैटर्न, अधिक जानकारी है: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx


सभी बिंदु पूरी तरह से उपयोग नहीं करने के बजाय इंजेक्शन के विभिन्न रूप का उपयोग करने के बारे में हैं। हालांकि लिंक के लिए +1।
जन हुदेक

3
सेवा लोकेटर एक विरोधी पैटर्न नहीं है और जिस व्यक्ति का ब्लॉग आप से जुड़ा हुआ है वह पैटर्न का विशेषज्ञ नहीं है। यह है कि वह StackExchange-प्रसिद्ध है सॉफ्टवेयर डिजाइन के लिए एक तरह से काम करता है। मार्टिन फाउलर (स्टेपल पैटर्न्स ऑफ़ एंटरप्राइज एप्लीकेशन आर्किटेक्चर के लेखक) का इस विषय पर अधिक उचित दृष्टिकोण है: martinfowler.com/articles/injection.html
कॉलिन

1
@ कोलिन, इसके विपरीत, सेवा लोकेटर निश्चित रूप से एक विरोधी पैटर्न है, और यहां संक्षेप में यही कारण है
Kyralessa

@Kyralessa - आपको एहसास है कि डीआई फ्रेमवर्क आंतरिक रूप से सेवाओं को देखने के लिए एक सर्विस लोकेटर पैटर्न का उपयोग करते हैं, है ना? ऐसी परिस्थितियां हैं जहां दोनों उपयुक्त हैं, और न ही एक विरोधी पैटर्न हैं, जबकि स्टैकएक्सचेंज से नफरत है, कुछ लोग डंप करना चाहते हैं।
कॉलिन

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

8

जब आप अपनी परियोजना को बनाए रखने और परीक्षण योग्य बनाकर कुछ हासिल करने के लिए खड़े नहीं होते हैं।

गंभीरता से, मैं सामान्य रूप से IoC और DI से प्यार करता हूं, और मैं कहूंगा कि 98% समय मैं उस पैटर्न का उपयोग बिना असफल हो जाएगा। यह एक बहु-उपयोगकर्ता वातावरण में विशेष रूप से महत्वपूर्ण है, जहां आपको अलग-अलग टीम के सदस्यों और विभिन्न परियोजनाओं द्वारा बार-बार पुन: उपयोग किया जा सकता है, क्योंकि यह तर्क को कार्यान्वयन से अलग करता है। लॉगिंग इसका एक प्रमुख उदाहरण है, कक्षा में इंजेक्ट किया गया एक ILog इंटरफ़ेस आपके लॉगिंग फ्रेमवर्क-डु-पत्रिकाओं में बस प्लग करने की तुलना में एक हज़ार गुना अधिक बनाए रखने योग्य है, क्योंकि आपके पास कोई गारंटी नहीं है कि कोई अन्य प्रोजेक्ट समान लॉगिंग फ़्रेमवर्क का उपयोग करेगा (यदि इसका उपयोग करता है) एक बिल्कुल!)।

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

सब के सब, यह किसी भी पद्धति या पैटर्न के लिए एक व्यावहारिक दृष्टिकोण लेने के लिए समझदार है, क्योंकि कुछ भी समय का 100% लागू नहीं होता है।

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


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

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

1

जबकि अन्य उत्तर तकनीकी पहलुओं पर ध्यान केंद्रित करते हैं, मैं एक व्यावहारिक आयाम जोड़ना चाहूंगा।

वर्षों से मैं एक निष्कर्ष पर आया था कि कई व्यावहारिक आवश्यकताएं हैं जिन्हें पूरा करने की आवश्यकता है अगर डिपेंडेंसी इंजेक्शन शुरू करना एक सफल होना है।

  1. इसे पेश करने का एक कारण होना चाहिए।

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

  2. टीम को प्रशिक्षित और बोर्ड पर होना चाहिए।

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

    यदि DI को टीम के नए सदस्य द्वारा पेश किया जाता है, क्योंकि वे इसे समझते हैं और इसे पसंद करते हैं और केवल यह दिखाना चाहते हैं कि वे अच्छे हैं, और टीम सक्रिय रूप से शामिल नहीं है, एक वास्तविक जोखिम है कि यह वास्तव में गुणवत्ता में कमी करेगा कोड।

  3. आपको परीक्षण करने की आवश्यकता है

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


1

यह एक पूर्ण उत्तर नहीं है, लेकिन सिर्फ एक बिंदु है।

जब आपके पास एक एप्लिकेशन होता है जो एक बार शुरू होता है, तो लंबे समय तक चलता है (एक वेब ऐप की तरह) DI अच्छा हो सकता है।

जब आपके पास एक एप्लिकेशन होता है जो कई बार शुरू होता है और कम समय (मोबाइल ऐप की तरह) के लिए चलता है तो आप शायद कंटेनर नहीं चाहते हैं।


मुझे यह नहीं दिखता कि DI से संबंधित आवेदन का लाइव समय कैसा है
माइकल फ्रीजिम

@MichaelFreidgeim संदर्भ को शुरू करने में समय लगता है, आमतौर पर DI कंटेनर स्प्रिंग जैसे काफी भारी होते हैं। केवल एक वर्ग के साथ एक हैलो वर्ल्ड ऐप बनाएं और स्प्रिंग के साथ एक बनाएं और दोनों 10 बार शुरू करें और आप देखेंगे कि मेरा क्या मतलब है।
कोरे तुगे

यह एक व्यक्ति DI कंटेनर के साथ एक मुद्दे की तरह लग रहा है। .Net दुनिया में मैंने DI कंटेनरों के लिए एक अनिवार्य समस्या के रूप में प्रारंभिक समय के बारे में नहीं सुना है
माइकल फ्रीजिम

1

बुनियादी OOP सिद्धांतों का उपयोग करने का प्रयास करें: उपयोग विरासत , आम कार्यक्षमता को निकालने के लिए संपुटित (छिपाने) बातें, जो निजी / आंतरिक / संरक्षित सदस्यों / प्रकार का उपयोग कर बाहर की दुनिया से रक्षा की जानी चाहिए। केवल परीक्षणों के लिए कोड इंजेक्षन करने के लिए किसी भी शक्तिशाली परीक्षण-ढांचे का उपयोग करें, उदाहरण के लिए https://www.typemock.com/ या https://www.telerik.com/products/mocking.aspx

फिर इसे DI के साथ फिर से लिखने की कोशिश करें, और कोड की तुलना करें, जो आप आमतौर पर DI के साथ देखेंगे:

  1. आपके पास अधिक इंटरफ़ेस (अधिक प्रकार) हैं
  2. आपने सार्वजनिक विधियों के हस्ताक्षरों के डुप्लिकेट बनाए हैं और आपको इसे डबल करना होगा (आप बस एक बार कुछ पैरामीटर नहीं बदल सकते हैं, आपको इसे दो बार करना होगा, मूल रूप से सभी रिफैक्टिंग और नेविगेशनल संभावनाएं अधिक जटिल हो सकती हैं)
  3. आपने समय विफलताओं को चलाने के लिए कुछ संकलन त्रुटियों को स्थानांतरित किया है (DI के साथ आप कोडिंग के दौरान कुछ निर्भरता को अनदेखा कर सकते हैं और यह सुनिश्चित नहीं कर सकते कि यह परीक्षण के दौरान उजागर हो जाएगा)
  4. आपने अपना एनकैप्सुलेशन खोला है। अब संरक्षित सदस्य, आंतरिक प्रकार आदि सार्वजनिक हो गए
  5. कुल मिलाकर कोड की मात्रा बढ़ाई गई

मैं कहूंगा कि मैंने जो देखा, लगभग हमेशा, DI के साथ कोड की गुणवत्ता कम हो रही है।

हालाँकि, यदि आप वर्ग घोषणा में केवल "सार्वजनिक" एक्सेस संशोधक का उपयोग करते हैं, और / या सदस्यों के लिए सार्वजनिक / निजी संशोधक, और / या आपके पास महंगे परीक्षण उपकरण खरीदने का विकल्प नहीं है और उसी समय आपको इकाई परीक्षण की आवश्यकता होती है जो ' टी को एकीकृत परीक्षण द्वारा प्रतिस्थापित किया जा सकता है, और / या आपके पास पहले से ही उन वर्गों के लिए इंटरफेस हैं जिन्हें आप इंजेक्ट करने के लिए सोच रहे हैं, डीआई एक अच्छा विकल्प है!

ps शायद मुझे इस पद के लिए बहुत सारे मंत्री मिलेंगे, मुझे विश्वास है क्योंकि अधिकांश आधुनिक डेवलपर्स अभी यह नहीं समझते हैं कि आंतरिक कीवर्ड का उपयोग कैसे और क्यों करना है और अपने घटकों के युग्मन को कैसे कम करना है और अंत में इसे कम क्यों करना है) अंत में, बस कोड और तुलना करने का प्रयास करें


0

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

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

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

TLDR : यदि आपकी कक्षा में स्थिर निर्भरताएँ हैं या आप विरासत कोड को फिर से ला रहे हैं, तो एक सेवा लोकेटर यकीनन DI से बेहतर है।


12
सेवा लोकेटर आपके कोड में निर्भरताएँ छुपाता है । यह उपयोग करने के लिए एक अच्छा पैटर्न नहीं है।
Kyralessa

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

@Kyralessa मैं सहमत हूं, एक सेवा लोकेटर में कई डाउनसाइड हैं और DI लगभग हमेशा बेहतर है। हालांकि, मेरा मानना ​​है कि नियम के कुछ अपवाद हैं, जैसा कि सभी प्रोग्रामिंग सिद्धांतों के साथ है।
गार्लेट हॉल

सेवा स्थान का मुख्य स्वीकृत उपयोग एक रणनीति पैटर्न के भीतर होता है, जहाँ "रणनीति बीनने वाले" वर्ग को उपयोग करने की रणनीति खोजने के लिए पर्याप्त तर्क दिया जाता है, और या तो इसे वापस सौंप दिया जाता है या इसके माध्यम से कॉल पास किया जाता है। यहां तक ​​कि इस मामले में, रणनीति बीनने वाले एक आईओसी कंटेनर द्वारा प्रदान की गई फैक्टरी विधि के लिए एक मुखौटा हो सकता है, जिसे एक ही तर्क दिया जाता है; कारण यह है कि आप इसे तोड़ देंगे जहां यह है और जहां यह सबसे छिपा है तर्क नहीं है।
कीथ

मार्टिन फाउलर को उद्धृत करने के लिए, "विन्यास से अलग करने के सिद्धांत की तुलना में (डीआई और सर्विस लोकेटर) के बीच का विकल्प कम महत्वपूर्ण है"। यह विचार है कि DI हमेशा बेहतर है हॉगवॉश। यदि कोई सेवा विश्व स्तर पर उपयोग की जाती है, तो DI का उपयोग करना अधिक बोझिल और भंगुर है। इसके अतिरिक्त, DI प्लगइन आर्किटेक्चर के लिए कम अनुकूल है जहां कार्यान्वयन रनटाइम तक ज्ञात नहीं हैं। सोचें कि डिबग.विराइटलाइन () और इस तरह के अतिरिक्त तर्कों को हमेशा के लिए कितना अजीब लगेगा!
कॉलिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.