मुझे निर्भरता इंजेक्शन का उपयोग क्यों करना चाहिए?


95

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

मुझे निम्नलिखित क्यों करना चाहिए?

class Profile {
    public function deactivateProfile(Setting $setting)
    {
        $setting->isActive = false;
    }
}

निम्नलिखित के बजाय?

class Profile {
    public function deactivateProfile()
    {
        $setting = new Setting();
        $setting->isActive = false;
    }
}

8
आप एक हार्ड-कोडित निर्भरता को शुरू करने के लिए शुरू कर रहे हैं। निष्क्रिय करना () (जो बुरा है)। आपके पास पहले एक में अधिक डिकोड्ड कोड है, जिससे इसे बदलना और परीक्षण करना आसान हो जाता है।
औलिस रोंकेनैन

3
आप पहला काम क्यों करेंगे? आप एक सेटिंग में गुजर रहे हैं और फिर उसके मूल्य की अनदेखी कर रहे हैं।
फिल एन डेब्लैंक

57
मैं चढ़ाव से सहमत नहीं हूँ। जबकि विषय वस्तु को विशेषज्ञों के लिए तुच्छ माना जा सकता है, प्रश्न में योग्यता है: यदि निर्भरता व्युत्क्रम का उपयोग किया जाना चाहिए, तो इसका उपयोग करने का औचित्य होना चाहिए।
फ्लोटर

13
@PhilNDeBlanc: यह कोड स्पष्ट रूप से वास्तविक दुनिया के तर्क का संकेतक नहीं है। हालांकि, deactivateProfileमुझे सुझाव देता है कि isActiveअपनी पिछली स्थिति की परवाह किए बिना झूठे को स्थापित करना यहां सही दृष्टिकोण है। विधि को स्वाभाविक रूप से कॉल करने का मतलब है कि आप इसे निष्क्रिय के रूप में सेट करने के लिए हैं , न कि इसकी वर्तमान (इन) सक्रिय स्थिति।
फ्लेटर

2
आपका कोड निर्भरता इंजेक्शन या उलटा का उदाहरण नहीं है। यह मानकीकरण का एक उदाहरण है (जो अक्सर DI की तुलना में बहुत बेहतर है)।
jpmc26

जवाबों:


104

लाभ यह है कि निर्भरता इंजेक्शन के बिना, आपका प्रोफ़ाइल वर्ग

  • सेटिंग्स ऑब्जेक्ट बनाने का तरीका जानने की आवश्यकता है (एकल जिम्मेदारी सिद्धांत का उल्लंघन करता है)
  • हमेशा अपनी सेटिंग ऑब्जेक्ट को उसी तरह बनाता है (दोनों के बीच एक तंग युग्मन बनाता है)

लेकिन निर्भरता इंजेक्शन के साथ

  • सेटिंग ऑब्जेक्ट बनाने का तर्क कहीं और है
  • विभिन्न प्रकार की सेटिंग्स ऑब्जेक्ट का उपयोग करना आसान है

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


23
This may seem (or even be) irrelevant in this particular caseमुझे लगता है कि यह वास्तव में बहुत अधिक प्रासंगिक है। आप सेटिंग्स कैसे प्राप्त करेंगे? बहुत सारे सिस्टम जो मैंने देखे हैं उनमें सेटिंग्स का एक हार्ड-कोडित डिफ़ॉल्ट सेट और एक सार्वजनिक सामना करने वाला कॉन्फ़िगरेशन होगा, इसलिए आपको दोनों को लोड करना होगा और सार्वजनिक सेटिंग्स के साथ कुछ मानों को अधिलेखित करना होगा। आपको चूक के कई स्रोतों की भी आवश्यकता हो सकती है। शायद आप भी डिस्क से कुछ हो रहे होंगे, अन्य DB से। तो, सेटिंग्स प्राप्त करने के लिए पूरा तर्क, और अक्सर, गैर-तुच्छ है - निश्चित रूप से कुछ खपत कोड नहीं होना चाहिए या इसके बारे में परवाह नहीं करनी चाहिए।
व्लाज

हम यह भी उल्लेख कर सकते हैं कि एक गैर-तुच्छ घटक के लिए वस्तु आरंभीकरण, जैसे कि वेब सेवा, $setting = new Setting();भयावह रूप से अक्षम बना देगा । इंजेक्शन और ऑब्जेक्ट इंस्टेंटेशन एक बार होता है।
वाइकिंगस्टेवेट

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

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

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

64

निर्भरता इंजेक्शन आपके कोड को जांचने में आसान बनाता है।

मैंने यह पहली बार सीखा जब मुझे Magento के PayPal एकीकरण में हार्ड-टू-कैच बग को ठीक करने का काम सौंपा गया था।

जब पेपल मैगेंटो को एक असफल भुगतान के बारे में बता रहा था, तो एक मुद्दा उठेगा: मैगेंटो असफलता को ठीक से पंजीकृत नहीं करेगा।

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

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

<?php
// This is the dependency we will inject to facilitate our testing
class MockHttpClient extends Varien_Http_Adapter_Curl {
    function read() {
        // Make Magento think that PayPal said "VERIFIED", no matter what they actually said...
        return "HTTP/1.1 200 OK\n\nVERIFIED";
    }
}

// Here, we trick Magento into thinking PayPal actually sent something back.
// Magento will try to verify it against PayPal's API though, and since it's fake data, it'll always fail.
$ipnPayload = array (
  'invoice'        => '100058137',         // Order ID to test against
  'txn_id'         => '04S87540L2309371A', // Test PayPal transaction ID
  'payment_status' => 'Failed'             // New payment status that Magento should ingest
);

// This is what Magento's controller calls during a normal IPN request.
// Instead of letting Magento talk to PayPal, we "inject" our fake HTTP client, which always returns VERIFIED.
Mage::getModel('paypal/ipn')->processIpnRequest($ipnPayload, new MockHttpClient());

मुझे यकीन है कि DI पैटर्न के अन्य फायदे बहुत हैं, लेकिन बढ़ी हुई परीक्षणशीलता मेरे दिमाग में एकमात्र सबसे बड़ा लाभ है

यदि आप इस समस्या के समाधान के बारे में उत्सुक हैं, तो यहाँ GitHub रेपो देखें : https://github.com/bubbleupdev/BUCorefix_Paypalstatus


4
निर्भरता इंजेक्शन कोड को हार्डकोडेड निर्भरता के साथ परीक्षण करने के लिए आसान बनाता है। पूरी तरह से व्यावसायिक तर्क से निर्भरता को खत्म करना और भी बेहतर है।
एंट पी

1
और @AntP क्या सुझाता है, इसका एक प्रमुख तरीका पैरामीटराइजेशन है । डेटाबेस से वापस आने वाले परिणामों को पृष्ठ टेम्पलेट भरने के लिए उपयोग किए जाने वाले परिणामों को बदलने के लिए तर्क (आमतौर पर "मॉडल" के रूप में जाना जाता है) को यह भी पता नहीं होना चाहिए कि एक भ्रूण हो रहा है; यह सिर्फ उन वस्तुओं को इनपुट के रूप में प्राप्त करने की आवश्यकता है।
jpmc26

4
@ jpmc26 वास्तव में - मैं कार्यात्मक कोर, अनिवार्य शेल के बारे में वीणा करता हूं , जो वास्तव में आपके डोमेन में डेटा को पारित करने के लिए निर्भरता को इंजेक्ट करने के बजाय सिर्फ एक फैंसी नाम है। डोमेन शुद्ध है, इकाई को बिना मोक्स के परीक्षण किया जा सकता है और फिर केवल एक शेल में लपेटा जाता है, जो दृढ़ता, संदेश आदि जैसी चीजों को लागू करता है
Ant P

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

26

क्यों (क्या मुद्दा भी है)?

मुझे निर्भरता इंजेक्शन का उपयोग क्यों करना चाहिए?

इसके लिए मुझे मिला सबसे अच्छा mnemonic " नया गोंद है ": हर बार जब आप newअपने कोड में उपयोग करते हैं, तो उस कोड को उस विशिष्ट कार्यान्वयन से नीचे बांधा जाता है । यदि आप बार-बार निर्माणकर्ताओं में नए का उपयोग करते हैं, तो आप विशिष्ट कार्यान्वयनों की एक श्रृंखला बनाएंगे । और क्योंकि आप इसे बनाए बिना किसी वर्ग का उदाहरण "नहीं" कर सकते हैं, आप उस श्रृंखला को अलग नहीं कर सकते।

एक उदाहरण के रूप में, कल्पना कीजिए कि आप एक रेस कार वीडियो गेम लिख रहे हैं। आपने एक वर्ग के साथ शुरुआत की Game, जो एक बनाता है RaceTrack, जो 8 बनाता है Cars, जो प्रत्येक एक बनाता है Motor। अब यदि आप Carsएक अलग त्वरण के साथ 4 अतिरिक्त चाहते हैं , तो आपको शायद छोड़कर हर वर्ग को बदलना होगा Game

क्लीनर कोड

क्या यह सिर्फ क्लीनर आर्किटेक्चर / कोड के लिए है

जी हां

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

List<Car> cars = new List<Car>();
for(int i=0; i<8; i++){
    float acceleration = 0.3f;
    float maxSpeed = 200.0f;
    Motor motor = new Motor(acceleration, maxSpeed);
    Car car = new Car(motor);
    cars.Add(car);
}
RaceTrack raceTrack = new RaceTrack(cars);
Game game = new Game(raceTrack);

उन 4 अलग-अलग कारों को जोड़कर अब इन लाइनों को जोड़कर किया जा सकता है:

for(int i=0; i<4; i++){
    float acceleration = 0.5f;
    float maxSpeed = 100.0f;
    Motor motor = new Motor(acceleration, maxSpeed);
    Car car = new Car(motor);
    cars.Add(car);
}
  • में कोई परिवर्तन नहीं RaceTrack, Game, Car, या Motorआवश्यक थे - जिसका मतलब है कि हम 100% यकीन है कि हम किसी भी नए कीड़े वहाँ परिचय नहीं था हो सकता है!
  • कई फ़ाइलों के बीच कूदने के बजाय, आप एक ही समय में अपनी स्क्रीन पर पूर्ण परिवर्तन देख पाएंगे। यह निर्माण / सेटअप / कॉन्फ़िगरेशन को अपनी जिम्मेदारी के रूप में देखने का एक परिणाम है - यह मोटर बनाने के लिए कार का काम नहीं है।

प्रदर्शन के विचार

या यह एक पूरे के रूप में प्रदर्शन को प्रभावित करता है?

नहीं । लेकिन आपके साथ पूरी तरह से ईमानदार होने के लिए, यह हो सकता है।

हालांकि, उस मामले में भी, यह इतनी हास्यास्पद छोटी राशि है कि आपको देखभाल करने की आवश्यकता नहीं है। भविष्य में कुछ बिंदु पर, आप 5 मेगाहर्ट्ज सीपीयू और 2 एमबी रैम के बराबर के साथ एक tamagotchi के लिए कोड लिखने के लिए है, तो हो सकता है आप कर सकते हैं इस बारे में देखभाल करने के लिए है।

99.999% * मामलों में इसका बेहतर प्रदर्शन होगा, क्योंकि आपने बग को ठीक करने में कम समय बिताया और अधिक समय अपने संसाधन-भारी एल्गोरिदम में सुधार किया।

* पूरी तरह से बना नंबर

जानकारी जोड़ी गई: "हार्ड-कोडेड"

कोई गलती मत करो, यह है अभी भी बहुत ज्यादा "हार्ड-कोडेड" - संख्या सीधे कोड में लिखा जाता है। हार्ड-कोडेड का मतलब कुछ ऐसा नहीं होगा जैसे उन मूल्यों को टेक्स्ट फ़ाइल में संग्रहीत करना - जैसे JSON प्रारूप में - और फिर उन्हें उस फ़ाइल से पढ़ना।

ऐसा करने के लिए, आपको एक फ़ाइल पढ़ने और फिर JSON को पार्स करने के लिए कोड जोड़ना होगा। यदि आप फिर से उदाहरण पर विचार करते हैं; गैर-डीआई संस्करण में, Carया Motorअब एक फ़ाइल को पढ़ना है। यह बहुत ज्यादा समझ में नहीं आता है।

DI संस्करण में, आप इसे गेम सेट करने वाले कोड में जोड़ देंगे।


3
विज्ञापन हार्ड-कोडित, कोड और कॉन्फिग फ़ाइल के बीच वास्तव में इतना अंतर नहीं है। एप्लिकेशन के साथ बंडल की गई फ़ाइल एक स्रोत है, भले ही आप गतिशील रूप से पढ़ें। कोड से लेकर डेटा फ़ाइलों को json या 'कॉन्फिग' फॉर्मेट में मान खींचना तब तक कुछ भी नहीं करता है जब तक कि उपयोगकर्ता द्वारा मानों को ओवरराइड नहीं किया जाना चाहिए या पर्यावरण पर निर्भर नहीं होना चाहिए।
Jan Hudec

3
मैंने वास्तव में एक Arduino (16MHz, 2KB) पर एक बार तमागाटोची बनाई थी
जुंगकुक

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

17

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

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

तो आपका प्रश्न लगभग "मेरे समारोह में तर्क क्यों लेना चाहिए?" के बराबर है। और कई समान उत्तर हैं, अर्थात्: कॉलर को निर्णय लेने के लिए

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

तो: क्या कोई विशेष कारण है जो आपको विशेष रूप से इस विशेष Settingप्रकार / मूल्य का उपयोग करने की आवश्यकता है ? क्या एक अच्छा कारण कॉलिंग कोड एक अलग Settingप्रकार / मूल्य चाहते हो सकता है ? (याद रखें, परीक्षण कोड हैं !)


2
हां। IoC ने आखिरकार मुझे क्लिक किया जब मुझे एहसास हुआ कि यह "कॉलर को निर्णय लेने" के बारे में है। उस IoC का अर्थ है घटक का नियंत्रण घटक के लेखक से घटक के उपयोगकर्ता में स्थानांतरित हो जाता है। और उस बिंदु के बाद से मैं पहले से ही सॉफ्टवेयर के साथ पर्याप्त पकड़ ले चुका हूं, जो खुद को मुझसे ज्यादा स्मार्ट समझता था, मुझे तुरंत डीआई दृष्टिकोण पर बेच दिया गया था।
जोकर_vD

1
"यह सिर्फ कार्यों के लिए तर्क गुजर रहा है। यह मुश्किल से एक पैटर्न में सब है" यह मैंने सुना है डि की ही अच्छा या यहाँ तक कि comprehendible विवरण है (अच्छी तरह से ज्यादातर लोगों को भी इस बारे में बात नहीं है कि यह क्या है , बल्कि अपने फायदे)। और फिर वे "नियंत्रण के व्युत्क्रम" और "ढीले युग्मन" जैसे जटिल शब्दजाल का उपयोग करते हैं, जिसे समझने के लिए अधिक प्रश्नों की आवश्यकता होती है जब यह वास्तव में सरल विचार होता है।
एडिसन

7

आप जो उदाहरण देते हैं वह शास्त्रीय अर्थों में निर्भरता इंजेक्शन नहीं है। निर्भरता इंजेक्शन आमतौर पर एक निर्माता में गुजर वस्तुओं को संदर्भित करता है या "सेटर इंजेक्शन" का उपयोग ऑब्जेक्ट के बनाए जाने के ठीक बाद करता है, ताकि एक नए बनाए गए ऑब्जेक्ट में एक क्षेत्र पर एक मूल्य निर्धारित किया जा सके।

आपका उदाहरण किसी ऑब्जेक्ट को आवृत्ति विधि के तर्क के रूप में पास करता है। यह उदाहरण विधि तब उस ऑब्जेक्ट पर फ़ील्ड को संशोधित करती है। निर्भरता अन्तःक्षेपण? नहीं। अतिक्रमण और डेटा छिपाना? पूर्ण रूप से!

अब, यदि कोड इस तरह था:

class Profile {
    private $settings;

    public function __construct(Settings $settings) {
        $this->settings = $settings;
    }

    public function deactive() {
        $this->settings->isActive = false;
    }
}

फिर मैं कहूंगा कि आप निर्भरता इंजेक्शन का उपयोग कर रहे हैं। उल्लेखनीय अंतर एक Settingsवस्तु है जो निर्माणकर्ता या एक Profileवस्तु को पारित किया जा रहा है ।

यह उपयोगी है यदि सेटिंग्स ऑब्जेक्ट निर्माण के लिए महंगा या जटिल है, या सेटिंग्स एक इंटरफ़ेस या अमूर्त वर्ग है जहां रन टाइम व्यवहार को बदलने के लिए कई ठोस कार्यान्वयन मौजूद हैं।

चूँकि आप किसी विधि को कॉल करने के बजाय सीधे सेटिंग ऑब्जेक्ट पर किसी क्षेत्र तक पहुँच बना रहे हैं, आप पॉलिमॉर्फिज्म का लाभ नहीं उठा सकते हैं, जो निर्भरता इंजेक्शन के लाभों में से एक है।

ऐसा लगता है कि किसी प्रोफ़ाइल के लिए सेटिंग उस प्रोफ़ाइल के लिए विशिष्ट है। इस मामले में मैं निम्नलिखित में से एक करूंगा:

  1. प्रोफ़ाइल निर्माता के अंदर सेटिंग्स ऑब्जेक्ट को तुरंत

  2. कंस्ट्रक्टर में सेटिंग्स ऑब्जेक्ट को पास करें और व्यक्तिगत क्षेत्रों पर कॉपी करें जो प्रोफ़ाइल पर लागू होता है

ईमानदारी से, सेटिंग ऑब्जेक्ट को अंदर deactivateProfileऔर फिर सेटिंग ऑब्जेक्ट के आंतरिक क्षेत्र को संशोधित करके एक कोड गंध है। सेटिंग्स ऑब्जेक्ट केवल एक ही होना चाहिए जो उसके आंतरिक क्षेत्रों को संशोधित कर रहा हो।


5
The example you give is not dependency injection in the classical sense.- कोई बात नहीं। OO लोगों के मस्तिष्क पर वस्तुएं होती हैं, लेकिन आप अभी भी किसी चीज पर
रॉबर्ट हार्वे

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

3
@ रोबर्टहवे: मुझे लगता है कि मैं "निर्भरता इंजेक्शन" के साथ बहुत अधिक स्वतंत्रता ले रहा था। जिस स्थान पर लोग अक्सर शब्द के बारे में सोचते हैं और शब्द का उपयोग करते हैं वह वस्तु निर्माण के समय किसी वस्तु पर "इंजेक्ट" होने के संदर्भ में है, या सेटर इंजेक्शन के मामले में तुरंत बाद।
ग्रेग बर्गहार्ट

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

7

मुझे पता है कि मैं इस पार्टी में देरी से आ रहा हूं लेकिन मुझे लगता है कि एक महत्वपूर्ण बिंदु याद किया जा रहा है।

मुझे ऐसा क्यों करना चाहिए:

class Profile {
    public function deactivateProfile(Setting $setting)
    {
        $setting->isActive = false;
    }
}

आपको नहीं करना चाहिए लेकिन इसलिए नहीं कि डिपेंडेंसी इंजेक्शन एक बुरा विचार है। ऐसा इसलिए है क्योंकि यह गलत कर रहा है।

कोड का उपयोग करके इस चीज़ को देखें। हम यह करने जा रहे हैं:

$profile = new Profile();
$profile->deactivateProfile($setting);

जब हम इसके बारे में एक ही बात करते हैं:

$setting->isActive = false; // Deactivate profile

तो बेशक यह समय की बर्बादी जैसा लगता है। यह तब होता है जब आप इसे इस तरह से करते हैं। यह निर्भरता इंजेक्शन का सबसे अच्छा उपयोग नहीं है। यह एक वर्ग का सबसे अच्छा उपयोग भी नहीं है।

अब क्या हुआ अगर इसके बजाय हमारे पास यह है:

$profile = new Profile($setting);

$application = new Application($profile);

$application.start();

और अब यह applicationसक्रिय रूप से सक्रिय करने और निष्क्रिय करने के लिए स्वतंत्र है profileविशेष रूप से कुछ के बारे में जानने के लिए settingकि यह वास्तव में बदल रहा है। वह अच्छा क्यों है? मामले में आपको सेटिंग बदलने की आवश्यकता है। applicationउन परिवर्तनों से बंद दीवारों है, ताकि आप सब कुछ तोड़ने जैसे ही आप कुछ स्पर्श के रूप में देखने के लिए बिना एक सुरक्षित निहित अंतरिक्ष में पागल हो जाना करने के लिए स्वतंत्र हैं।

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

परिणाम यह तय करने के लिए आपके पास एक अलग जगह है कि क्या और क्या करने के लिए एक अलग जगह को जोड़ता है जो कि क्या कहता है।

कोशिश करें कि किसी ऐसी चीज पर जिसे आप समय के साथ बनाए रखें और देखें कि यह मदद नहीं करती है।


6

एक ग्राहक के रूप में, जब आप अपनी कार के लिए कुछ करने के लिए एक मैकेनिक को नियुक्त करते हैं, तो क्या आप उम्मीद करते हैं कि मैकेनिक खरोंच से कार बनाने के लिए तभी उसके साथ काम करेगा? नहीं, आप मैकेनिक को वह कार देते हैं जिसे आप चाहते हैं कि वे काम करें

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

हम ऐसा क्यों करते हैं? खैर, इसके बारे में सोचो। आप एक गैरेज मालिक हैं जो किसी को अपने मैकेनिक बनने के लिए किराए पर लेना चाहता है। आप उन्हें एक मैकेनिक होना सिखाएँगे (= आप कोड लिखेंगे)।

क्या आसान होने जा रहा है:

  • एक मैकेनिक को सिखाएं कि एक पेचकश का उपयोग करके कार को स्पॉइलर कैसे संलग्न किया जाए।
  • एक कार बनाने के लिए एक मैकेनिक को सिखाएं, एक बिगाड़ने वाला बनाएं, एक पेचकश बनाया और फिर नए बनाए गए बिगाड़ने वाले को नई बनाई गई कार के साथ नए पेचकश के साथ संलग्न करें।

अपने मैकेनिक को खरोंच से सब कुछ नहीं बनाने के बड़े पैमाने पर लाभ हैं:

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

यदि आप विशेषज्ञ मैकेनिक को किराए पर लेते हैं और प्रशिक्षित करते हैं, तो आप एक ऐसे कर्मचारी के साथ समाप्त होने जा रहे हैं, जिसके पास अधिक लागत है, जो कि एक साधारण काम करने के लिए अधिक समय लेता है, और जब भी उनकी कई जिम्मेदारियों में से एक की आवश्यकता होगी, तब उसे हमेशा के लिए वापस लेने की आवश्यकता होगी। अद्यतन किया जाएगा।

विकास की समानता यह है कि यदि आप हार्डकोड निर्भरता के साथ कक्षाओं का उपयोग करते हैं, तो आप उन कक्षाओं को बनाए रखने के लिए मुश्किल से समाप्त होने जा रहे हैं, जिन्हें निरंतर पुनर्विकास / परिवर्तनों की आवश्यकता होगी जब भी ऑब्जेक्ट का नया संस्करण ( Settingsआपके मामले में) बनाया जाता है, और आप 'विभिन्न प्रकार की Settingsवस्तुओं को बनाने की क्षमता रखने वाले वर्ग के लिए आंतरिक तर्क विकसित करना होगा ।

इसके अलावा, जो कोई भी आपकी कक्षा का उपभोग करता है, उसे अब कक्षा को सही वस्तु बनाने के लिए कहना होगा Settings, क्योंकि कक्षा को किसी भी Settingsवस्तु को पारित करने में सक्षम होने का विरोध करने के लिए। इसका मतलब यह है कि उपभोक्ता को यह पता लगाने के लिए कि सही उपकरण बनाने के लिए कक्षा से कैसे पूछा जाए।


हां, निर्भरता को हार्डकोड करने के बजाय निर्भरता व्युत्क्रम को लिखने के लिए थोड़ा अधिक प्रयास करना पड़ता है। हां, अधिक टाइप करना कष्टप्रद है।

लेकिन यह वही तर्क है जो हार्डकोड शाब्दिक मूल्यों को चुनना है क्योंकि "घोषित चर अधिक प्रयास लेता है"। तकनीकी रूप से सही है, लेकिन परिमाण के कई आदेशों द्वारा समर्थक को पछाड़ दिया है

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


यह एक पूरे के रूप में प्रदर्शन को प्रभावित करता है?

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


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

12
मुझे लगता है कि पूरी कार की बात थोड़ी बेतुकी और भ्रमित करने वाली है
इवान

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

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

2
@ जीबीजैनब: किसी भी बिंदु पर मेरा जवाब दूर से भी बहुरूपता में नहीं उतरता। कोई उत्तराधिकार, इंटरफ़ेस कार्यान्वयन, या कुछ भी प्रकार के अप / डाउनकास्टिंग जैसा नहीं है। आप जवाब को पूरी तरह से गलत बता रहे हैं।
फ्लेवर

0

सभी पैटर्न की तरह, फूले हुए डिजाइनों से बचने के लिए "क्यों" पूछना बहुत मान्य है।

निर्भरता इंजेक्शन के लिए, यह आसानी से दो के बारे में सोचकर देखा जाता है, यकीनन, ओओपी डिजाइन के सबसे महत्वपूर्ण पहलू ...

कम युग्मन

कंप्यूटर प्रोग्रामिंग में युग्मन :

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

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

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

उच्च सामंजस्य

सामंजस्य :

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

यह सिक्के का दूसरा पहलू है। यदि आप कोड की एक इकाई (एक विधि, एक वर्ग, एक पैकेज इत्यादि) को देखते हैं, तो आप चाहते हैं कि उस इकाई के अंदर सभी कोड यथासंभव कम जिम्मेदारियां हों।

इसके लिए एक मूल उदाहरण MVC पैटर्न होगा: आप स्पष्ट रूप से डोमेन मॉडल को दृश्य (GUI) और एक नियंत्रण परत से अलग करते हैं जो एक साथ चमकते हैं।

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

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


-1

आपको उन समस्याओं को हल करने के लिए तकनीकों का उपयोग करना चाहिए जो आपके पास उन समस्याओं को हल करने में अच्छी हैं। निर्भरता उलटा और इंजेक्शन अलग नहीं हैं।

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

हम फ़ंक्शन के कार्यान्वयन को अलग क्यों करना चाहते हैं? इसके दो मुख्य कारण हैं:

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

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

thing5 =  new MyThing5();
thing3 = new MyThing3(thing5, new MyThing10());

myApp = new MyApp(
    new MyAppDependency1(thing5, thing3),
    new MyAppDependency2(
        new Thing1(),
        new Thing2(new Thing3(thing5, new Thing4(thing5)))
    ),
    ...
    new MyAppDependency15(thing5)
);

यह आपको अपनी कक्षाएं पंजीकृत करने देता है और फिर आपके लिए निर्माण करता है:

injector.register(Thing1); // Yes, you'd need some kind of actual class reference.
injector.register(Thing2);
...
injector.register(MyAppDepdency15);
injector.register(MyApp);

myApp = injector.create(MyApp); // The injector fills in all the construction parameters.

ध्यान दें कि यह सबसे सरल है यदि पंजीकृत कक्षाएं स्टेटलेस सिंगललेट हो सकती हैं ।

सावधानी का शब्द

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

myAverageAboveMin()
{
    dbConn = new DbConnection("my connection string");
    dbQuery = dbConn.makeQuery();
    dbQuery.Command = "SELECT * FROM MY_DATA WHERE x > :min";
    dbQuery.setParam("min", 5);
    dbQuery.Execute();
    myData = dbQuery.getAll();
    count = 0;
    total = 0;
    foreach (row in myData)
    {
        count++;
        total += row.x;
    }

    return total / count;
}

हम इस पद्धति के कुछ हिस्सों के लिए निर्भरता व्युत्क्रम का उपयोग कर सकते हैं:

class MyQuerier
{
    private _dbConn;

    MyQueries(dbConn) { this._dbConn = dbConn; }

    fetchAboveMin(min)
    {
        dbQuery = this._dbConn.makeQuery();
        dbQuery.Command = "SELECT * FROM MY_DATA WHERE x > :min";
        dbQuery.setParam("min", min);
        dbQuery.Execute();
        return dbQuery.getAll();
    }
}


class Averager
{
    private _querier;

    Averager(querier) { this._querier = querier; }

    myAverageAboveMin(min)
    {
        myData = this._querier.fetchAboveMin(min);
        count = 0;
        total = 0;
        foreach (row in myData)
        {
            count++;
            total += row.x;
        }

        return total / count;
    }

लेकिन हमें कम से कम पूरी तरह से नहीं होना चाहिए। ध्यान दें कि हमने एक स्टेटफुल क्लास बनाई है Querier। यह अब कुछ अनिवार्य रूप से वैश्विक कनेक्शन ऑब्जेक्ट के लिए एक संदर्भ रखता है। इससे कार्यक्रम की समग्र स्थिति को समझने में कठिनाई होती है और विभिन्न वर्ग एक दूसरे के साथ समन्वय कैसे करते हैं। ध्यान दें कि यदि हम औसत तर्क का परीक्षण करना चाहते हैं, तो हमें क्वायर या कनेक्शन को नकली करने के लिए मजबूर किया जाता है। इसके अलावा एक बेहतर दृष्टिकोण को बढ़ाने के लिए किया जाएगा parameterization :

class MyQuerier
{
    fetchAboveMin(dbConn, min)
    {
        dbQuery = dbConn.makeQuery();
        dbQuery.Command = "SELECT * FROM MY_DATA WHERE x > :min";
        dbQuery.setParam("min", min);
        dbQuery.Execute();
        return dbQuery.getAll();
    }
}


class Averager
{
    averageData(myData)
    {
        count = 0;
        total = 0;
        foreach (row in myData)
        {
            count++;
            total += row.x;
        }

        return total / count;
    }

class StuffDoer
{
    private _querier;
    private _averager;

    StuffDoer(querier, averager)
    {
        this._querier = querier;
        this._averager = averager;
    }

    myAverageAboveMin(dbConn, min)
    {
        myData = this._querier.fetchAboveMin(dbConn, min);
        return this._averager.averageData(myData);
    }
}

और कनेक्शन को कुछ और भी उच्च स्तर पर प्रबंधित किया जाएगा जो एक पूरे के रूप में ऑपरेशन के लिए जिम्मेदार है और जानता है कि इस आउटपुट के साथ क्या करना है।

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


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

@DavidArno हाँ, आप सही कह रहे हैं। मैंने शब्दावली समायोजित कर ली है।
jpmc26

कार्यान्वयन को अलग करने का तीसरा मुख्य कारण है, या कम से कम कोड को यह मानते हुए डिज़ाइन करना कि कार्यान्वयन अलग-अलग हो सकता है: यह डेवलपर को ढीले युग्मन के लिए प्रोत्साहित करता है और कोड लिखने से बचना चाहिए जो बदलने के लिए कठिन होगा एक नया कार्यान्वयन किसी समय में लागू किया जाना चाहिए। भविष्य। और जबकि यह कुछ परियोजनाओं में प्राथमिकता नहीं हो सकती है (जैसे कि यह जानते हुए कि एप्लिकेशन को इसकी प्रारंभिक रिलीज के बाद कभी भी दोबारा नहीं देखा जाएगा), यह दूसरों में होगा (उदाहरण के लिए, जहां कंपनी व्यवसाय मॉडल विशेष रूप से अपने अनुप्रयोगों के विस्तारित समर्थन / विस्तार की पेशकश करने की कोशिश करता है। )।
7

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

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