धीरे-धीरे कोडबेस को निर्भरता इंजेक्शन कंटेनर में ले जाएं


9

मेरे पास बहुत सारे "एंटी-पैटर्न" सिंगलेट्स के साथ एक बड़ा कोडबेस है, स्टेटिक तरीकों के साथ यूटिलिटी क्लासेस और newकीवर्ड का उपयोग करके अपनी खुद की निर्भरता पैदा करने वाली कक्षाएं । यह परीक्षण करने के लिए एक कोड को बहुत कठिन बनाता है।

मैं धीरे-धीरे कोड को निर्भरता इंजेक्शन कंटेनर में स्थानांतरित करना चाहता हूं (मेरे मामले में यह है Guice, क्योंकि यह एक GWTपरियोजना है)। निर्भरता इंजेक्शन की मेरी समझ से, यह सब या कुछ भी नहीं है। या तो सभी कक्षाएं स्प्रिंग / गाइस द्वारा प्रबंधित की जाती हैं या कोई भी नहीं। चूंकि कोडबेस बड़ा है इसलिए मैं रात में कोड को रूपांतरित नहीं कर सकता। इसलिए मुझे इसे धीरे-धीरे करने का एक तरीका चाहिए।

समस्या यह है कि जब मैं एक ऐसे वर्ग से शुरू करता हूं जिसे अन्य वर्गों में इंजेक्ट करने की आवश्यकता होती है, तो मैं @Injectउन वर्गों में एक सरल का उपयोग नहीं कर सकता , क्योंकि उन वर्गों को अभी तक कंटेनर द्वारा प्रबंधित नहीं किया गया है। तो यह "टॉप" वर्गों तक एक लंबी श्रृंखला बनाता है जो कहीं भी इंजेक्ट नहीं होते हैं।

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

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

ऐसे क्रमिक प्रवासन को प्राप्त करने का तरीका क्या होगा?

पुनश्च निर्भरता इंजेक्शन के लिए क्रमिक दृष्टिकोण शीर्षक के समान है, लेकिन यह मेरे प्रश्न का उत्तर नहीं देता है।


1
क्या आप एक निर्भरता इंजेक्शन कंटेनर का उपयोग करने के लिए कठिन युग्मित कक्षाएं होने से सीधे जाना चाहते हैं? आपको पहले किसी भी निर्भरता इंजेक्शन ढांचे या उपकरण से शादी करने से पहले इंटरफेस का उपयोग करते हुए, वर्गों को डिकूप करने के लिए कुछ रिफैक्टिंग करना होगा।
ट्यूलेंस कोर्डोवा

काफी उचित। इसलिए मेरे पास कुछ उपयोगिता वर्ग ए है जो 30 अन्य वर्गों (उनमें से एक वर्ग बी) में उपयोग किया जाता है, उन्हें अप्राप्य बनाता है। मैंने कक्षा ए को कक्षा बी का एक निर्माता निर्भरता बनाने के बारे में सोचा। मुझे सभी कॉल को निर्माणकर्ताओं को बदलना होगा और ए को अंदर पारित करना होगा। लेकिन मुझे इसे कहां से प्राप्त करना चाहिए?
दमलु

यदि बी सबसे छोटी इकाई है तो आरंभ करने के लिए आप डीआई को आवेदन कर सकते हैं, तो मुझे ए का निर्माण करने में कोई नुकसान नहीं है जहां भी आप समय के लिए बी का निर्माण कर रहे हैं - बशर्ते ए में कोई निर्भरता नहीं है। एक बार गेंद लुढ़कने के बाद, आप वापस आ सकते हैं और इसे रिफैक्ट कर सकते हैं।
एंडी हंट

@ कद्दू एक कारखाने के साथ शुरू करने के लिए?
ट्यूलेंस कोर्डोवा

1
@ कदली वर्ग केवल इसलिए अप्रतिष्ठित नहीं हो जाता कि वह उपयोगिता वर्ग पर निर्भर है। इसका मतलब सिर्फ यह है कि आपकी इकाई जितना आप चाहते हैं उससे थोड़ा बड़ा है। यदि आप अपने उपयोगिता वर्ग का परीक्षण स्वयं कर सकते हैं, तो आप बिना किसी चिंता के अन्य सभी 30 कक्षाओं के परीक्षणों में इसका उपयोग कर सकते हैं। यूनिट परीक्षण के बारे में मार्टिन फाउलर ब्लॉग पढ़ें।
gbjbaanb

जवाबों:


2

माफ़ C#करना मेरी पसंद की भाषा है, मैं इसे पढ़ सकता हूँ Javaलेकिन शायद कसाई वाक्य लिखने की कोशिश कर रहा होगा ... एक ही अवधारणा के बीच C#और Javaहालांकि लागू होता है , इसलिए उम्मीद है कि यह चरणों को दिखाएगा कि कैसे आप धीरे-धीरे अपने कोड आधार को और अधिक बढ़ा सकते हैं परीक्षण योग्य।

दिया हुआ:

public class MyUI
{
    public void SomeMethod()
    {
        Foo foo = new Foo();
        foo.DoStuff();
    }
}

public class Foo
{

    public void DoStuff()
    {
        Bar bar = new Bar();
        bar.DoSomethingElse();
    }

}

public class Bar
{
    public void DoSomethingElse();
}

आईओसी कंटेनर के उपयोग के बिना, डीआई का उपयोग करने के लिए आसानी से रिफैक्ट किया जा सकता है - और आप संभवतः इसे कई चरणों में तोड़ भी सकते हैं:

(संभावित) एक कदम - निर्भरता में ले लेकिन कॉलिंग (यूआई) कोड में कोई परिवर्तन नहीं:

public class MyUI
{
    public void SomeMethod()
    {
        Foo foo = new Foo();
        foo.DoStuff();
    }
}

public class Foo
{

    private IBar _iBar;

    // Leaving this constructor for step one, 
    // so that calling code can stay as is without impact
    public Foo()
    {
        _iBar = new Bar();
    }

    // simply because we now have a constructor that take's in the implementation of the IBar dependency, 
    // Foo can be much more easily tested.
    public Foo(IBar iBar)
    {
        _iBar = iBar;
    }

    public void DoStuff()
    {
        _iBar.DoSomethingElse();
    }

}

public interface IBar
{
    void DoSomethingElse();
}

public class Bar
{
    public void DoSomethingElse();
}

आईओसी कंटेनर को लागू करने और तुरंत कॉलिंग कोड बदलने पर रिफ्लेक्टर 2 (या पहला रिफ्लेक्टर):

public class MyUI
{
    public void SomeMethod()
    {
        Foo foo = null // use your IOC container to resolve the dependency
        foo.DoStuff();
    }
}

public class Foo
{

    private IBar _iBar;

    // note we have now dropped the "default constructor" - this is now a breaking change as far as the UI is concerned.
    // You can either do this all at once (do only step 2) or in a gradual manner (step 1, then step 2)

    // Only entry into class - requires passing in of class dependencies (IBar)
    public Foo(IBar iBar)
    {
        _iBar = iBar;
    }

    public void DoStuff()
    {
        _iBar.DoSomethingElse();
    }

}

चरण 2 तकनीकी रूप से स्वयं द्वारा किया जा सकता है - लेकिन (संभावित रूप से) बहुत अधिक काम होगा - इस बात पर निर्भर करता है कि आप वर्तमान में DI को कितनी कार्यक्षमता दिखा रहे हैं, "कितने नए" हैं।

चरण 1 -> चरण 2 मार्ग के साथ जाने पर विचार करें - आप Fooस्वतंत्र के लिए इकाई परीक्षण बनाने में सक्षम होंगे Bar। जबकि चरण 1 रिफ्लेक्टर से पहले इसे दोनों वर्गों के वास्तविक कार्यान्वयन का उपयोग किए बिना आसानी से पूरा नहीं किया गया था। चरण 1 -> चरण 2 (तुरंत चरण 2 के बजाय) समय के साथ छोटे बदलावों की अनुमति देगा, और आपके पास पहले से ही एक परीक्षण दोहन की शुरुआत होगी ताकि बेहतर परिणाम सुनिश्चित करने के लिए आपका रिफ्लेक्टर काम कर सके।


0

अवधारणा वही है चाहे आप जावा, पीएचपी, या यहां तक ​​कि सी # का उपयोग कर रहे हों। इस प्रश्न को इस YouTube वीडियो में जेम्मा एनीबल द्वारा काफी अच्छी तरह से निपटा गया है:

https://www.youtube.com/watch?v=Jccq_Ti8Lck (PHP, क्षमा करें!)

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

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