निर्भरता इंजेक्शन का उपयोग करते समय एक कक्षा में कितने इंजेक्शन स्वीकार्य हैं


9

मैं निर्भरता इंजेक्शन के लिए C # में एकता का उपयोग कर रहा हूं, लेकिन यह प्रश्न किसी भी भाषा और ढांचे के लिए लागू होना चाहिए जो निर्भरता इंजेक्शन का उपयोग कर रहा है।

मैं एसओएलआईडी-सिद्धांत का पालन करने की कोशिश कर रहा हूं और इसलिए मुझे बहुत सार मिला है। लेकिन अब मैं सोच रहा हूं कि एक इंजेक्शन एक वर्ग को कितने इंजेक्शन लगाने चाहिए?

उदाहरण के लिए, मेरे पास 9 इंजेक्शन के साथ एक भंडार है। क्या दूसरे डेवलपर के लिए पढ़ना मुश्किल होगा?

इंजेक्शन में निम्नलिखित जिम्मेदारियां हैं:

  • IDbContextFactory - डेटाबेस के लिए संदर्भ बनाना।
  • IMapper - संस्थाओं से डोमेन मॉडल के लिए मानचित्रण।
  • IClock - Abstracts DateTime.Now इकाई परीक्षणों में मदद करने के लिए।
  • IPerformanceFactory - विशिष्ट तरीकों के लिए निष्पादन समय को मापता है।
  • ILog - लॉगिंग के लिए Log4net।
  • ICollectionWrapperFactory - संग्रह बनाता है (जो IEnumerable का विस्तार करता है)।
  • IQueryFilterFactory - इनपुट के आधार पर क्वेरीज़ उत्पन्न करता है जो db क्वेरी करेगा।
  • IIdentityHelper - उपयोगकर्ता में लॉग इन प्राप्त करता है।
  • IFaultFactory - अलग-अलग FaultException बनाएं (मैं WCF का उपयोग करता हूं)।

मैं वास्तव में असंतुष्ट नहीं हूं कि मैंने जिम्मेदारियों को कैसे सौंपा, लेकिन मैं पठनीयता के लिए चिंतित होना शुरू कर रहा हूं।

तो, मेरे सवाल:

क्या किसी वर्ग को कितने इंजेक्शन लगाने चाहिए? और यदि हां, तो इससे कैसे बचें?

क्या कई इंजेक्शन पठनीयता को सीमित करते हैं, या क्या यह वास्तव में इसमें सुधार करता है?


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

3
कितने निर्माता तर्क स्वीकार्य हैं? IoC वह नहीं बदलता है
तेलस्तीन

लोग हमेशा पूर्ण सीमाएं क्यों चाहते हैं?
मार्जन वेनमा

1
@ टेलस्टाइन: जरूरी नहीं। IoC परिवर्तन क्या है कि स्थिर वर्गों / एकल / वैश्विक चर पर निर्भर होने के बजाय, सभी निर्भरता अधिक केंद्रीकृत और अधिक "दृश्यमान" हैं।
आर्सेनी मूरज़ेंको

@ मार्जनवीनेमा: क्योंकि यह जीवन को बहुत आसान बनाता है। यदि आप किसी विधि पर अधिकतम LOC प्रति विधि या किसी विधि में अधिकतम संख्या या चर पर अधिकतम संख्या जानते हैं, और केवल यही एक चीज है जो मायने रखती है, तो कोड को अच्छे या बुरे के रूप में अर्हता प्राप्त करना आसान हो जाता है, जैसे कि बुरा कोड "ठीक" के रूप में। यह दुर्भाग्यपूर्ण है कि वास्तविक जीवन इससे कहीं अधिक जटिल है और कई मैट्रिक्स ज्यादातर अप्रासंगिक हैं।
आर्सेनी मूरज़ेंको

जवाबों:


11

बहुत अधिक निर्भरता संकेत कर सकती है कि वर्ग स्वयं बहुत अधिक काम कर रहा है। यह निर्धारित करने के लिए कि क्या यह बहुत अधिक नहीं कर रहा है:

  • कक्षा को ही देखिए। क्या इसे दो, तीन, चार में विभाजित करने का कोई मतलब होगा? क्या यह समझ में आता है?

  • निर्भरता के प्रकारों को देखें। कौन से डोमेन-विशिष्ट हैं, और कौन से "वैश्विक" हैं? उदाहरण के लिए, मैं ILogएक ही स्तर पर विचार नहीं करूंगा IQueryFilterFactory: यदि वे लॉगिंग का उपयोग कर रहे हैं तो पहले वाला अधिकांश व्यावसायिक वर्गों में उपलब्ध होगा। दूसरी ओर, यदि आपको बहुत अधिक डोमेन-विशिष्ट निर्भरताएँ मिलती हैं, तो यह संकेत दे सकता है कि वर्ग बहुत अधिक काम कर रहा है।

  • उन निर्भरताओं को देखें जिन्हें मूल्यों द्वारा प्रतिस्थापित किया जा सकता है।

    IClock - Abstracts DateTime.Now इकाई परीक्षणों में मदद करने के लिए।

    इसे आसानी से उन DateTime.Nowतरीकों से बदला जा सकता है जिन्हें वर्तमान समय में जानना आवश्यक है।

वास्तविक निर्भरता को देखकर, मुझे ऐसी कोई भी चीज नहीं दिखती जो खराब चीजों के संकेत दे रही हो:

  • IDbContextFactory - डेटाबेस के लिए संदर्भ बनाना।

    ठीक है, हम शायद एक व्यावसायिक परत के अंदर हैं जहाँ कक्षाएं डेटा एक्सेस परत के साथ बातचीत करती हैं। ठीक लग रहा है।

  • IMapper - संस्थाओं से डोमेन मॉडल के लिए मानचित्रण।

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

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

  • IClock - Abstracts DateTime.Now इकाई परीक्षणों में मदद करने के लिए।

    वर्तमान समय में सिर्फ पाने के लिए एक अलग इंटरफ़ेस (और वर्ग) रखना बहुत उपयोगी नहीं है। मैं बस DateTime.Nowउन तरीकों को पास करूंगा जिनके लिए वर्तमान समय की आवश्यकता है।

    यदि कोई अन्य जानकारी है, जैसे टाइमज़ोन, या दिनांक सीमाएँ आदि, तो एक अलग वर्ग समझ में आ सकता है।

  • IPerformanceFactory - विशिष्ट तरीकों के लिए निष्पादन समय को मापता है।

    अगला बिंदु देखें

  • ILog - लॉगिंग के लिए Log4net।

    इस तरह की ट्रांसेंडेंट कार्यक्षमता फ्रेमवर्क से संबंधित होनी चाहिए, और वास्तविक पुस्तकालयों को रनटाइम के दौरान विनिमेय और कॉन्फ़िगर करने योग्य होना चाहिए (उदाहरण के लिए .NET में app.config के माध्यम से)।

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

    यदि लाइब्रेरी का उपयोग करने के लिए बहुत जटिल है, तो एक मुखौटा पैटर्न समझ में आता है।

  • ICollectionWrapperFactory - संग्रह बनाता है (जो IEnumerable का विस्तार करता है)।

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

  • IQueryFilterFactory - इनपुट के आधार पर क्वेरीज़ उत्पन्न करता है जो db क्वेरी करेगा।

    डेटा एक्सेस लेयर में ऐसा क्यों नहीं है? Filterनाम में एक क्यों है ?

  • IIdentityHelper - उपयोगकर्ता में लॉग इन प्राप्त करता है।

    मुझे यकीन नहीं है कि एक Helperप्रत्यय क्यों है । सभी मामलों में, अन्य प्रत्यय या तो विशेष रूप से स्पष्ट नहीं होंगे ( IIdentityManager?)

    वैसे भी, यहाँ इस निर्भरता का सही अर्थ है।

  • IFaultFactory - अलग-अलग FaultException बनाएं (मैं WCF का उपयोग करता हूं)।

    यह तर्क इतना जटिल है कि इसे एक कारखाने के पैटर्न का उपयोग करने की आवश्यकता है? उसके लिए डिपेंडेंसी इंजेक्शन का उपयोग क्यों किया जाता है? क्या आप उत्पादन कोड और परीक्षणों के बीच अपवादों के निर्माण की अदला-बदली करेंगे? क्यों?

    मैं इसे सरल बनाने की कोशिश करूंगा throw new FaultException(...)। यदि क्लाइंट को प्रचारित करने से पहले सभी अपवादों में कुछ वैश्विक जानकारी जोड़ी जानी चाहिए, तो शायद WCF के पास एक ऐसा तंत्र है, जहां आप एक बिना अपवाद के अपवाद को पकड़ सकते हैं और इसे बदलकर ग्राहक को वापस ला सकते हैं।

क्या किसी वर्ग को कितने इंजेक्शन लगाने चाहिए? और यदि हां, तो इससे कैसे बचें?

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

क्या कई इंजेक्शन पठनीयता को सीमित करते हैं, या क्या यह वास्तव में इसमें सुधार करता है?

निर्भरता के बहुत से तर्क का पालन करना अधिक कठिन हो जाता है। यदि तर्क का पालन करना मुश्किल है, तो वर्ग संभवतः बहुत अधिक कर रहा है और विभाजित होना चाहिए।


आप टिप्पणियों और अपने समय के लिए धन्यवाद। ज्यादातर फॉल्टफैक्ट्री के बारे में जो इसके बजाय डब्ल्यूसीएफ-लॉजिक में ले जाए जाएंगे। जब मैं TDD- आईएनजी एक आवेदन है, तो मैं IClock रखूंगा। कई बार जब आप यह सुनिश्चित करना चाहते हैं कि निश्चित समय के साथ एक विशिष्ट मूल्य निर्धारित किया गया था। तब DateTime.Now हमेशा पर्याप्त नहीं होगा क्योंकि यह नकली नहीं है।
धूम्रपान करने वालों को

7

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

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

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

अपने अंतिम प्रश्नों का उत्तर देने के लिए:

  • क्या एक वर्ग के पास कितनी निर्भरता होनी चाहिए, इसकी कोई ऊपरी सीमा है?

हां, ऊपरी सीमा "बहुत अधिक" है। कितना अधिक, बहुत अधिक है"? "बहुत अधिक" तब होता है जब कक्षा का सामंजस्य "बहुत कम" हो जाता है। यह सब निर्भर करता है। आम तौर पर अगर किसी वर्ग के लिए आपकी प्रतिक्रिया "वाह, इस बात पर बहुत अधिक निर्भरता है", तो यह बहुत ज्यादा है।

  • क्या इंजेक्शन निर्भरता में सुधार या पठनीयता पर चोट लगती है?

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

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


1
अच्छी प्रतिक्रिया। धन्यवाद। हां, ऊपरी सीमा "बहुत अधिक" है। - शानदार, और इतना सच है।
धूम्रपान

3

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

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

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