इस तरह से मैं यह कोड लिख रहा हूं, यह परीक्षण योग्य है, लेकिन क्या इसमें कुछ गड़बड़ है जो मुझे याद आ रही है?


13

मेरे पास एक इंटरफ़ेस है IContext। इसके उद्देश्यों के लिए यह वास्तव में मायने नहीं रखता कि यह निम्नलिखित को छोड़कर क्या करता है:

T GetService<T>();

यह विधि क्या करती है आवेदन के वर्तमान डीआई कंटेनर को देखें और निर्भरता को हल करने का प्रयास करें। काफी हद तक मानक मुझे लगता है।

ASP.NET MVC एप्लिकेशन में, मेरा निर्माता इस तरह दिखता है।

protected MyControllerBase(IContext ctx)
{
    TheContext = ctx;
    SomeService = ctx.GetService<ISomeService>();
    AnotherService = ctx.GetService<IAnotherService>();
}

इसलिए प्रत्येक सेवा के लिए कंस्ट्रक्टर में कई मापदंडों को जोड़ने के बजाय (क्योंकि इससे एप्लिकेशन को बढ़ाने वाले डेवलपर्स के लिए वास्तव में कष्टप्रद और समय लेने वाला हो जाएगा) मैं सेवाओं को प्राप्त करने के लिए इस पद्धति का उपयोग कर रहा हूं।

अब, यह गलत लगता है । हालांकि, जिस तरह से मैं अभी अपने सिर में इसे सही ठहरा रहा हूं वह यह है - मैं इसका मजाक उड़ा सकता हूं

हाँ मैं। IContextनियंत्रक का परीक्षण करना कठिन नहीं होगा । मुझे वैसे भी करना होगा:

public class MyMockContext : IContext
{
    public T GetService<T>()
    {
        if (typeof(T) == typeof(ISomeService))
        {
            // return another mock, or concrete etc etc
        }

        // etc etc
    }
}

लेकिन जैसा कि मैंने कहा, यह गलत लगता है। किसी भी विचार / दुरुपयोग का स्वागत करते हैं।


8
इसे सेवा लोकेटर कहा जाता है और मुझे यह पसंद नहीं है। इस विषय पर बहुत कुछ लिखा गया है - एक स्टार्टर के लिए martinfowler.com/articles/injection.html और blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern देखें ।
बेंजामिन हॉजसन

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

8
वह सही है, यह खराब डिजाइन है। यह आसान है public SomeClass(Context c):। यह कोड काफी स्पष्ट है, है ना? यह बताता है, that SomeClassएक पर निर्भर करता है Context। इर, लेकिन रुको, यह नहीं है! यह केवल Xप्रसंग से निर्भरता पर निर्भर करता है । इसका मतलब है कि हर बार जब आप इसमें बदलाव करते हैं तो Contextयह टूट सकता हैSomeObject , भले ही आप केवल Contextएस बदल गए हों Y। लेकिन हाँ, आप जानते हैं कि आपने केवल बदलाव Yनहीं किया है X, इसलिए SomeClassयह ठीक है। लेकिन अच्छा कोड लिखना इस बात के बारे में नहीं है कि आप क्या जानते हैं बल्कि नया कर्मचारी क्या जानता है जब वह पहली बार आपके कोड को देखता है।
वैलेंट्री 14

@DocBrown मेरे लिए वही है जो मैंने कहा था - मुझे यहाँ अंतर नहीं दिखता। क्या आप कृपया आगे बता सकते हैं?
वलंट्री

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

जवाबों:


5

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

आपका पहला उदाहरण बदल सकता है

protected MyControllerBase(IContext ctx)
{
    TheContext = ctx;
    SomeService = ctx.GetSomeService();
    AnotherService = ctx.GetAnotherService();
}

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

  • सुनिश्चित करें TheContext, SomeServiceऔर AnotherServiceहमेशा सभी नकली वस्तुओं, या वास्तविक वस्तुओं के साथ उन सभी के साथ आरंभिक हैं
  • या, 3 वस्तुओं के विभिन्न संयोजनों के साथ उन्हें आरंभ करने की अनुमति देने के लिए (जिसका अर्थ है, इस मामले के लिए आपके मापदंडों को व्यक्तिगत रूप से पारित करने की आवश्यकता होगी)

इसलिए कंस्ट्रक्टर में 3 के बजाय केवल एक पैरामीटर का उपयोग करना पूरी तरह से उचित हो सकता है।

जो चीज समस्याग्रस्त है IContextवह GetServiceसार्वजनिक रूप से विधि को उजागर कर रही है। IMHO आपको इससे बचना चाहिए, इसके बजाय "फ़ैक्टरी विधियों" को स्पष्ट रखें। तो इसे लागू करने के लिए ठीक हो जाएगा GetSomeServiceऔर GetAnotherServiceएक सेवा लोकेटर उपयोग करते हुए मेरे उदाहरण से तरीकों? IMHO जो निर्भर करता है। जब तक IContextवर्ग सेवा वस्तुओं की एक स्पष्ट सूची प्रदान करने के विशिष्ट उद्देश्य के लिए एक साधारण सार कारखाने का निर्माण कर रहा है, वह IMHO स्वीकार्य है। अमूर्त कारखाने आम तौर पर सिर्फ "गोंद" कोड होते हैं, जिन्हें इकाई-परीक्षण करने की आवश्यकता नहीं होती है। फिर भी आपको अपने आप से पूछना चाहिए कि क्या विधियों के संदर्भ में GetSomeService, यदि आपको वास्तव में एक सेवा लोकेटर की आवश्यकता है, या यदि एक स्पष्ट निर्माता कॉल सरल नहीं होगी।

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


मैं इससे सहमत हु। उदाहरण के साथ समस्या सामान्य GetServiceविधि है। स्पष्ट रूप से नामित और टाइप किए गए तरीकों से संपर्क करना बेहतर है। बेहतर अभी भी IContextनिर्माण में स्पष्ट रूप से कार्यान्वयन की निर्भरता को बाहर करना होगा ।
बेंजामिन हॉजसन

1
@BenjaminHodgson: यह कभी-कभी बेहतर हो सकता है, लेकिन यह हमेशा बेहतर नहीं होता है। जब कोड पैरामीटर सूची लंबी और लंबी हो जाती है तो आप कोड गंध पर ध्यान दें। मेरा पूर्व उत्तर यहाँ देखें: programmers.stackexchange.com/questions/190120/…
Doc Brown

@DocBrown ओवर-इंजेक्शन के कंस्ट्रक्टर की "कोड गंध" SRP के उल्लंघन का संकेत है, जो वास्तविक समस्या है। बस कई सेवाओं को एक मुखौटा श्रेणी में लपेटकर, केवल उन्हें गुणों के रूप में उजागर करने के लिए, मुद्दे के स्रोत को संबोधित करने के लिए कुछ भी नहीं करता है । इस प्रकार एक मुखौटा को अन्य घटकों के आसपास एक साधारण आवरण नहीं होना चाहिए, लेकिन आदर्श रूप से एक सरलीकृत एपीआई की पेशकश करनी चाहिए जिसके द्वारा उन्हें उपभोग करने के लिए (या उन्हें किसी अन्य तरीके से सरल करना चाहिए) ...
एलेक्सफॉक्सगिल

... याद रखें कि कंस्ट्रक्टर ओवर-इंजेक्शन की तरह "कोड गंध" अपने आप में कोई समस्या नहीं है। यह सिर्फ एक संकेत है कि कोड में एक गहरी समस्या है जिसे आमतौर पर समस्या की पहचान होने पर समझदारी से
रिफ्लेक्ट

जब Microsoft ने इसमें सेंध लगाई तो आप कहां थे IValidatableObject?
रबरडक

15

इस डिजाइन को सेवा लोकेटर * के रूप में जाना जाता है और मुझे यह पसंद नहीं है। इसके खिलाफ बहुत सारे तर्क हैं:

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

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

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

सेवा लोकेटर लिस्कोव प्रतिस्थापन सिद्धांत का उल्लंघन करता है । क्योंकि इसका व्यवहार प्रकार तर्क के आधार पर भिन्न होता है, सेवा लोकेटर को देखा जा सकता है जैसे कि यह प्रभावी रूप से इंटरफ़ेस पर अनंत प्रकार की विधियाँ रखता है! इस तर्क को यहाँ विस्तार से लिखा गया है

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

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

* मैं एक सामान्य Resolve<T>विधि के साथ एक वस्तु के रूप में सेवा लोकेटर को परिभाषित कर रहा हूं जो मनमाने ढंग से निर्भरता को हल करने में सक्षम है और पूरे कोडबेस में उपयोग किया जाता है (न कि केवल कम्पोजीशन रूट पर)। यह सेवा के रूप में समान नहीं है (एक वस्तु जो निर्भरता के कुछ छोटे ज्ञात सेट को बंडल करती है) या एब्सट्रैक्ट फैक्ट्री (एक ऐसी वस्तु जो एक प्रकार के उदाहरण बनाती है - एक सार फैक्ट्री का प्रकार सामान्य हो सकता है लेकिन विधि नहीं है) ।


1
आप सेवा लोकेटर पैटर्न (जो मुझे सहमत हैं) के बारे में शिकायत कर रहे हैं। लेकिन वास्तव में, ओपी के उदाहरण में, MyControllerBaseन तो एक विशिष्ट DI कंटेनर के लिए युग्मित है, और न ही यह "वास्तव में" सेवा लोकेटर विरोधी पैटर्न के लिए एक उदाहरण है।
डॉक्टर ब्राउन

@DocBrown मैं सहमत हूँ। इसलिए नहीं कि यह मेरे जीवन को आसान बनाता है, बल्कि इसलिए कि ऊपर दिए गए अधिकांश उदाहरण मेरे कोड के लिए प्रासंगिक नहीं हैं।
LiverpoolsNumber9

2
मेरे लिए, सेवा लोकेटर विरोधी पैटर्न की पहचान सामान्य GetService<T>पद्धति है। मनमानी निर्भरता को हल करना वास्तविक गंध है, जो ओपी के उदाहरण में मौजूद और सही है।
बेंजामिन हॉजसन

1
सेवा लोकेटर का उपयोग करने के साथ एक और समस्या यह है कि यह लचीलापन कम कर देता है: आपके पास प्रत्येक सेवा इंटरफ़ेस का केवल एक कार्यान्वयन हो सकता है। यदि आप दो वर्गों का निर्माण करते हैं जो एक IFrobnicator पर निर्भर करते हैं, लेकिन बाद में निर्णय लेते हैं कि एक को आपके मूल DefaultFrobnicator कार्यान्वयन का उपयोग करना चाहिए, लेकिन दूसरे को वास्तव में इसके आसपास CacheingFrobnicator डेकोरेटर का उपयोग करना चाहिए, आपको मौजूदा कोड बदलना होगा, जबकि यदि आप सीधे तौर पर आपको जो कुछ करना है, उस पर निर्भरता को इंजेक्ट करते हुए, अपना सेटअप कोड (या डिफॉल्ट फ़ाइल का उपयोग करें यदि आप डीआई फ्रेमवर्क का उपयोग कर रहे हैं) को बदल दें। इस प्रकार यह एक OCP उल्लंघन है।
जूल्स

1
@DocBrown GetService<T>()विधि मनमानी कक्षाओं को अनुरोध करने की अनुमति देती है: "यह विधि आवेदन के वर्तमान डीआई कंटेनर को देखती है और निर्भरता को हल करने का प्रयास करती है। मुझे लगता है कि मानक।" । मैं इस उत्तर के शीर्ष पर आपकी टिप्पणी का जवाब दे रहा था। यह 100% एक सेवा लोकेटर है
एलेक्सफॉक्सगिल

5

सेवा लोकेटर विरोधी पैटर्न के खिलाफ सबसे अच्छे तर्क मार्क सेमैन द्वारा स्पष्ट रूप से कहा गया है इसलिए मैं बहुत ज्यादा नहीं जाऊंगा कि यह एक बुरा विचार क्यों है - यह एक सीखने की यात्रा है जिसे आपको अपने लिए समझने के लिए समय निकालना होगा (I मार्क की पुस्तक की भी सिफारिश करें )।

प्रश्न का उत्तर देने के लिए ठीक है - अपनी वास्तविक समस्या को फिर से बताएं :

इसलिए प्रत्येक सेवा के लिए कंस्ट्रक्टर में कई मापदंडों को जोड़ने के बजाय (क्योंकि इससे एप्लिकेशन का विस्तार करने वाले डेवलपर्स के लिए वास्तव में कष्टप्रद और समय लेने वाला होगा) मैं सेवाओं को प्राप्त करने के लिए इस पद्धति का उपयोग कर रहा हूं।

एक सवाल है जो StackOverflow पर इस मुद्दे को संबोधित करता है । जैसा कि वहाँ एक टिप्पणी में उल्लिखित है:

सबसे अच्छी टिप्पणी: "कंस्ट्रक्टर इंजेक्शन के अद्भुत लाभों में से एक यह है कि यह सिंगल रिस्पॉन्सिबिलिटी प्रिंसिपल फ्रीजर के उल्लंघन को स्पष्ट करता है।"

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

परियोजनाओं मैं जहां एक बेस नियंत्रक पर काम किया है के सभी में, यह इस तरह के रूप सुविधाजनक गुण और विधियों, साझा करने के प्रयोजनों के लिए विशुद्ध रूप से किया गया था IsUserLoggedIn()और GetCurrentUserId()बंद करो । यह वंशानुक्रम का भयानक दुरुपयोग है। इसके बजाय, एक घटक बनाएं जो इन तरीकों को उजागर करता है और उस पर एक निर्भरता लेता है जहां आपको इसकी आवश्यकता होती है। इस तरह, आपके घटक परीक्षण योग्य रहेंगे और उनकी निर्भरता स्पष्ट होगी।

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

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


+1 - यह इस सवाल पर एक नया कदम है जिसमें से किसी भी अन्य उत्तर को वास्तव में संबोधित नहीं किया गया है
बेंजामिन होडसन

1
"कंस्ट्रक्टर इंजेक्शन के अद्भुत लाभों में से एक यह है कि यह एकल जिम्मेदारी सिद्धांत के उल्लंघन को स्पष्ट रूप से स्पष्ट करता है" लव। वास्तव में अच्छा जवाब। इससे सभी सहमत नहीं हैं। मेरा उपयोग मामला है, मजेदार रूप से पर्याप्त है, एक प्रणाली में डुप्लिकेट कोड न होने पर जिसमें 100 से अधिक नियंत्रक (कम से कम) होंगे। हालांकि, SRP - प्रत्येक इंजेक्शन सेवा की एक ही जिम्मेदारी है, जैसा कि नियंत्रक जो उन सभी का उपयोग करता है - कोई कैसे अपवर्तक करेगा ??
लिवरपूल

1
@ LiverpoolsNumber9 कुंजी बेसकंट्रोलर से कार्यक्षमता को निर्भरता में स्थानांतरित करने के लिए है, जब तक कि आपके पास protectedनए घटकों के लिए एक-लाइनर प्रतिनिधिमंडल को छोड़कर बेसकंट्रोलर में कुछ भी नहीं बचा है । फिर आप बेसकंट्रोलर को खो सकते हैं और उन protectedविधियों को निर्भरता के लिए सीधे कॉल के साथ बदल सकते हैं - यह आपके मॉडल को सरल करेगा और आपके सभी निर्भरता को स्पष्ट करेगा (जो कि 100 के साथ नियंत्रकों की एक परियोजना में बहुत अच्छी बात है!)
एलेक्सफॉक्सग्रेन

@ LiverpoolsNumber9 - यदि आप अपने बेसकंट्रोलर के एक हिस्से को एक
पास्टबिन में

-2

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

डॉक्टर ब्राउन के "सर्विस फेसेड" उत्तर मैंने इस उत्तर को स्वीकार कर लिया क्योंकि मैं जो खोज रहा था (यदि उत्तर "नहीं" था) कुछ उदाहरण या कुछ विस्तार था जो मैं कर रहा था। उन्होंने यह सुझाव देते हुए कहा कि A) इसे एक नाम मिला है, और B) ऐसा करने के बेहतर तरीके हैं।

बेंजामिन हॉजसन के "सर्विस लोकेटर" का जवाब जितना मैंने यहां प्राप्त ज्ञान की सराहना की है, मेरे पास जो है वह "सर्विस लोकेटर" नहीं है। यह एक "सेवा मुखौटा" है। इस उत्तर में सब कुछ सही है लेकिन मेरी परिस्थितियों के लिए नहीं।

यूएसआर के जवाब

मैं इसे और अधिक विस्तार से निपटाऊंगा:

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

मैं किसी भी टूलिंग को नहीं खोता और मैं कोई भी "स्थिर" टाइपिंग नहीं खो रहा हूँ। सेवा मोहरा वापस आ जाएगा जो मैंने अपने DI कंटेनर में कॉन्फ़िगर किया है, या default(T)। और जो लौटाता है वह "टाइप" होता है। प्रतिबिंब ढह जाता है।

मैं यह नहीं देखता कि कंस्ट्रक्टर के तर्क के रूप में अतिरिक्त सेवाओं को जोड़ना एक बड़ा बोझ क्यों है।

यह निश्चित रूप से "दुर्लभ" नहीं है। जैसा कि मैं एक आधार नियंत्रक का उपयोग कर रहा हूं , हर बार जब मुझे इसे बदलने की आवश्यकता होती है, तो मुझे 10, 100, 1000 अन्य नियंत्रकों को बदलना पड़ सकता है।

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

मैं निर्भरता इंजेक्शन का उपयोग कर रहा हूं। यही तो बात है।

और अंत में, जूल्स ने बेंजामिन के जवाब पर टिप्पणी की मैं कोई लचीलापन नहीं खो रहा हूं। यह मेरा सेवा कार्य है। मैं कई मापदंडों को जोड़ सकता हूं GetService<T>क्योंकि मैं अलग-अलग कार्यान्वयन के बीच अंतर करना चाहता हूं, जैसे कि एक डीआई कंटेनर को कॉन्फ़िगर करते समय कोई भी करेगा। इसलिए उदाहरण के लिए, मैं इस "संभावित समस्या" को प्राप्त GetService<T>()करने के GetService<T>(string extraInfo = null)लिए बदल सकता हूं ।


वैसे भी, हर किसी के लिए फिर से धन्यवाद। यह वास्तव में उपयोगी रहा है। चीयर्स।


4
मैं असहमत हूं कि आपके यहां एक सेवा का काम है। GetService<T>()विधि (प्रयास करने के लिए) संकल्प करने में सक्षम है मनमाने ढंग से निर्भरता । जैसा कि मैंने अपने जवाब के फुटनोट में बताया है, यह एक सर्विस लोकेटर है, सर्विस फेस नहीं है। यदि आप इसे एक छोटे सेट GetServiceX()/ GetServiceY()विधियों के साथ बदलना चाहते हैं, जैसा कि @DocBrown बताता है, तो यह एक मुखौटा होगा।
बेंजामिन हॉजसन

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

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

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

2
@ LiverpoolsNumber9 गलत: आपके परीक्षणों को अब पॉप्युलेट करना है IContextऔर उसे इंजेक्ट करना है, और महत्वपूर्ण रूप से: यदि आप एक नई निर्भरता जोड़ते हैं, तो कोड अभी भी संकलित करेगा - भले ही परीक्षण रनटाइम में विफल हो जाए
एलेक्सफॉक्सग्रेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.