मॉकिंग उत्पादन कोड में हैंडलिंग का परिचय देता है


15

एक IReader इंटरफ़ेस, IReader इंटरफ़ेस Reader कार्यान्वयन, और एक वर्ग ReaderConsumer का कार्यान्वयन जो पाठक से डेटा का उपभोग और प्रसंस्करण करता है।

public interface IReader
{
     object Read()
}

कार्यान्वयन

public class ReaderImplementation
{
    ...
    public object Read()
    {
        ...
    }
}

उपभोक्ता:

public class ReaderConsumer()
{
    public string location

    // constructor
    public ReaderConsumer()
    {
        ...
    }

    // read some data
    public object ReadData()
    {
        IReader reader = new ReaderImplementation(this.location)
        data = reader.Read()
        ...
        return processedData    
    }
}

ReaderConsumer के परीक्षण और प्रसंस्करण के लिए मैं IReader के एक मॉक का उपयोग करता हूं। तो ReaderConsumer बन जाता है:

public class ReaderConsumer()
{
    private IReader reader = null

    public string location

    // constructor
    public ReaderConsumer()
    {
        ...
    }

    // mock constructor
    public ReaderConsumer(IReader reader)
    {
        this.reader = reader
    }

    // read some data
    public object ReadData()
    {
        try
        {
            if(this.reader == null)
            {
                 this.reader = new ReaderImplementation(this.location)
            }

            data = reader.Read()
            ...
            return processedData    
        }
        finally
        {
            this.reader = null
        }
    }
}

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

यह लिखने के दौरान मुझे पता चलता है कि कोशिश-अंत में कुछ हद तक असंबंधित है क्योंकि यह अनुप्रयोग चलाने के समय के दौरान स्थान बदलने वाले उपयोगकर्ता को संभालने के लिए है।

कुल मिलाकर यह बदबूदार लगता है, इसे बेहतर तरीके से कैसे संभाला जा सकता है?


16
आमतौर पर, यह कोई समस्या नहीं है क्योंकि आश्रित के साथ कंस्ट्रक्टर इंजेक्ट किया गया एकमात्र निर्माता होगा। क्या यह ReaderConsumerस्वतंत्र होने के सवाल से बाहर है ReaderImplementation?
क्रिस वोहर्ट

वर्तमान में निर्भरता को दूर करना कठिन होगा। इसे थोड़ा और देखने से मुझे सिर्फ रीडरइम्प्लिमेंटेशन पर निर्भरता से ज्यादा गहरी समस्या है। चूंकि ReaderConsumer एक कारखाने से स्टार्टअप के दौरान बनाया गया है, यह एप्लिकेशन के जीवनकाल के माध्यम से जारी रहता है, और उपयोगकर्ताओं से परिवर्तन को स्वीकार करता है इसके लिए कुछ अतिरिक्त मालिश की आवश्यकता होती है। संभवतः कॉन्फ़िगरेशन / उपयोगकर्ता इनपुट एक ऑब्जेक्ट के रूप में मौजूद हो सकता है और उसके बाद ReaderConsumer और ReaderImplementation मक्खी पर बनाया जा सकता है। दोनों दिए गए उत्तर बहुत अच्छी तरह से अधिक सामान्य मामले को हल करती है।
क्रिस्चियन मो

3
जी हां । यह टीडीडी का बिंदु है: परीक्षण लिखने के लिए पहले एक अधिक विघटित डिजाइन का अर्थ है (अन्यथा आप इकाई विवरण नहीं लिख सकते हैं )। यह कोड को अधिक बनाए रखने में मदद करता है और एक्स्टेंसिबल भी है।
बकरीउ

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

जवाबों:


67

अपनी विधि से पाठक को आरंभ करने के बजाय, इस पंक्ति को आगे बढ़ाएं

{
    this.reader = new ReaderImplementation(this.location)
}

डिफ़ॉल्ट पैरामीटर रहित निर्माता में।

public ReaderConsumer()
{
    this.reader = new ReaderImplementation(this.location)
}

public ReaderConsumer(IReader reader)
{
    this.reader = reader
}

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


3
++ ++ ... एक डीआई दृष्टिकोण के अलावा, वह डिफ़ॉल्ट कंस्ट्रक्टर निश्चित रूप से एक कोड गंध है।
मथिउ गुइंडन

3
@ चटाई का डिफ़ॉल्ट तयशुदा कार्यान्वयन गलत नहीं है। Ctor चाइनिंग की कमी यहाँ की गंध है। =;) -
रबरडक

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

3
@ MatMug: आप डि कुत्ते की व्याख्या कर रहे हैं। यदि आपको डिफ़ॉल्ट कंस्ट्रक्टर को इंजेक्ट करने की आवश्यकता नहीं है, तो आप नहीं करते हैं।
रॉबर्ट हार्वे

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

54

आपको केवल एकल निर्माता की आवश्यकता है:

public class ReaderConsumer()
{
    private IReader reader = null

    public string location

    // constructor
    public ReaderConsumer(IReader reader)
    {
        this.reader = reader;
    }

अपने उत्पादन कोड में:

var rc = new ReaderConsumer(new ReaderImplementation(0));

आपके परीक्षण में:

var rc = new ReaderConsumer(new MockImplementation(0));

13

निर्भरता इंजेक्शन और नियंत्रण के व्युत्क्रम में देखें

इवान और रबरडक दोनों के पास उत्कृष्ट उत्तर हैं। लेकिन मैं यह देखने के लिए एक अन्य क्षेत्र का उल्लेख करना चाहता था जिसमें डिपेंडेंसी इंजेक्शन (DI) और इनवर्टर ऑफ कंट्रोल (IoC) हो। इन दोनों तरीकों से आप उस समस्या को हल करते हैं जो आप एक फ्रेमवर्क / लाइब्रेरी में अनुभव कर रहे हैं ताकि आपको इसके बारे में चिंता न करनी पड़े।

आपका उदाहरण सरल है, और इसके साथ जल्दी से दूर हो गया है, लेकिन, अनिवार्य रूप से आप इस पर निर्माण करने जा रहे हैं और आप या तो टनल्स के निर्माण या आरंभीकरण रूटीन के साथ समाप्त हो जाएंगे जो इस तरह दिखते हैं:

var फू = नया फू (नया बार (नया बाज), नया क्वेज़ ()), नया फू 2 ());

DI / IoC के साथ आप एक पुस्तकालय का उपयोग करते हैं जो आपको कार्यान्वयन के लिए इंटरफेस के मिलान के लिए नियमों को बाहर करने की अनुमति देता है और फिर आप बस "मुझे एक फू दें" कहते हैं और यह काम करता है कि यह सब कैसे वायर किया जाए।

वहाँ बहुत सारे दोस्ताना आईओसी कंटेनर हैं (जैसा कि उन्हें कहा जाता है) वहां से बाहर हैं, और मैं एक को देखने के लिए सिफारिश करने जा रहा हूं, लेकिन, कृपया पता लगाएं, क्योंकि बहुत अच्छे विकल्प हैं।

के साथ शुरू करने के लिए एक सरल है:

http://www.ninject.org/

यहाँ एक सूची का पता लगाने के लिए है:

http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx


7
इवान के और रबरडक दोनों के उत्तर डीआई प्रदर्शित करते हैं । DI / IoC किसी टूल या फ्रेमवर्क के बारे में नहीं है, यह कोड को इस तरह से आर्किटेक्चर और संरचित करने के बारे में है कि नियंत्रण उलटा है और निर्भरताएं इंजेक्ट की जाती हैं। मार्क सीमन की पुस्तक यह बताती है कि DI / IoC एक IoC फ्रेमवर्क के बिना पूरी तरह से कैसे प्राप्त किया जा सकता है, यह समझाने में एक महान (भयानक!) काम करता है, और क्यों और कब एक IoC फ्रेमवर्क एक अच्छा विचार बन जाता है (संकेत: जब आप पर निर्भरता की निर्भरता की निर्भरता है .. ।) =)
मैथ्यू गुइंडन

इसके अलावा ... +1 क्योंकि निनॉज भयानक है, और आपके जवाब को फिर से पढ़ने पर ठीक लगता है। पहला पैराग्राफ थोड़ा पढ़ता है जैसे ईवान का और रबरडक के उत्तर डीआई के बारे में नहीं हैं, हालांकि, जिसने मेरी पहली टिप्पणी को प्रेरित किया।
मथिउ गुइंडन

1
@ मैट की मग निश्चित रूप से आपकी बात है। मैं ओपी को डीआई / आईओसी में देखने के लिए प्रोत्साहित करने की कोशिश कर रहा था जो अन्य पोस्टर थे, वास्तव में, (एवान है गरीब आदमी के डीआई) का उपयोग करते हुए, लेकिन उल्लेख नहीं किया। निश्चित रूप से, एक फ्रेमवर्क का उपयोग करने का लाभ यह है कि यह उपयोगकर्ता को DI की दुनिया में बहुत सारे ठोस उदाहरणों के साथ डुबो देगा, जो उम्मीद करते हैं कि उन्हें समझने के लिए मार्गदर्शन करेंगे कि वे क्या कर रहे हैं ... हालांकि ... हमेशा नहीं। :-) और, निश्चित रूप से, मुझे मार्क सेमैन की पुस्तक बहुत पसंद थी। यह मेरे पसंदीदा में से एक है।
रेगिनाल्ड ब्लू

एक DI ढांचे के बारे में टिप के लिए धन्यवाद, यह इस गंदगी को ठीक से रिफ्लेक्टर करने का तरीका लगता है :)
kristian mo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.