खोज…


टिप्पणियों

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

if (DateTime.Now.Date > processDate)
{
    // Do some processing
}

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

आईओसी सिस्टम

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

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

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

यह खपत वर्गों को निर्भरता का प्रबंधन करने से मुक्त करता है।

कंस्ट्रक्टर इंजेक्शन

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

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

public class RecordProcessor
{
    readonly private ILogger _logger;

    public RecordProcessor(ILogger logger)
    {
        _logger = logger;
    }

    public void DoSomeProcessing() {
        // ...
        _logger.Log("Complete");
    }
}

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

इसके लिए सबसे उपयुक्त निम्नलिखित होगा:

[Test]
public void RecordProcessor_DependencyInjectionExample()
{
    ILogger logger = new FakeLoggerImpl(); //or create a mock by a mocking Framework
    
    var sut = new RecordProcessor(logger); //initialize with fake impl in testcode

    Assert.IsTrue(logger.HasCalledExpectedMethod());
}

संपत्ति इंजेक्शन

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

उस वर्ग पर विचार करें जिसे त्रुटि स्थिति में लॉग फ़ाइल में लिखने की आवश्यकता है। वर्ग जानता है कि कैसे एक डिफ़ॉल्ट Logger निर्माण करना है, लेकिन यह संपत्ति के इंजेक्शन के माध्यम से ओवरराइड करने की अनुमति देता है। हालांकि यह ध्यान देने योग्य Worths कि इस तरह से आप कस की एक सटीक कार्यान्वयन के साथ इस वर्ग के युग्मन कर रहे हैं का उपयोग कर संपत्ति इंजेक्शन ILogger है कि ConcreteLogger इस दिए गए उदाहरण में। एक संभावित समाधान एक कारखाना हो सकता है जो आवश्यक ILogger कार्यान्वयन देता है।

public class RecordProcessor
{
    public RecordProcessor()
    {
        Logger = new ConcreteLogger();
    }

    public ILogger Logger { get; set; }

    public void DoSomeProcessing()
    {
        // ...
        _logger.Log("Complete");
    }
}

ज्यादातर मामलों में, कन्स्ट्रक्टर इंजेक्शन प्रॉपर्टी इंजेक्शन के लिए बेहतर है क्योंकि यह इसके निर्माण के तुरंत बाद वस्तु की स्थिति के बारे में बेहतर गारंटी प्रदान करता है।

विधि इंजेक्शन

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

public void ProcessRecords(DateTime currentDate)
{
    foreach(var record in _records) 
    {
        if (currentDate.Date > record.ProcessDate)
        {
            // Do some processing
        }
    }
}

कंटेनर / DI चौखटे

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

इन वर्गों पर विचार करें:

public interface ILogger {
    void Log(string message);
}

public class ConcreteLogger : ILogger
{
    public ConcreteLogger()
    {
        // ...
    }
    public void Log(string message)
    {
        // ...
    }
}
public class SimpleClass
{
    public SimpleClass()
    {
        // ...
    }
}

public class SomeProcessor
{
    public SomeProcessor(ILogger logger, SimpleClass simpleClass)
    {
        // ...
    }
}

SomeProcessor निर्माण के लिए ILogger और SimpleClass दोनों की आवश्यकता होती है। यूनिटी जैसा कंटेनर इस प्रक्रिया को स्वचालित करने में मदद करता है।

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

// Register the container
var container = new UnityContainer();

// Register a type mapping.  This allows a `SimpleClass` instance
// to be constructed whenever it is required.
container.RegisterType<SimpleClass, SimpleClass>();

// Register an instance.  This will use this instance of `ConcreteLogger` 
// Whenever an `ILogger` is required.
container.RegisterInstance<ILogger>(new ConcreteLogger());

कंटेनर कॉन्फ़िगर किए जाने के बाद, इसका उपयोग ऑब्जेक्ट बनाने के लिए किया जा सकता है, स्वचालित रूप से आवश्यकतानुसार निर्भरता को हल करते हुए:

var processor = container.Resolve<SomeProcessor>();


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow