c# - एक निर्भरता इंजेक्शन का उपयोग क्यों करता है?


मैं निर्भरता इंजेक्शन (डीआई) को समझने की कोशिश कर रहा हूं, और एक बार फिर मैं विफल रहा। यह सिर्फ मूर्खतापूर्ण लगता है। मेरा कोड कभी गड़बड़ नहीं है; मैं मुश्किल से आभासी कार्यों और इंटरफेस (हालांकि मैं एक बार नीला चन्द्रमा में करता हूं) लिखता हूं और मेरे सारे कॉन्फ़िगरेशन को json.net (कभी-कभी एक XML सीरियलइज़र का उपयोग करके) क्लास में जादुई रूप से क्रमबद्ध किया जाता है।

मुझे यह समझ में नहीं आता है कि यह समस्या क्या हल करती है यह कहने का एक तरीका दिखता है: "नमस्ते। जब आप इस फ़ंक्शन में चले जाते हैं, तो इस प्रकार के ऑब्जेक्ट को वापस लौटें और इन पैरामीटर / डेटा का उपयोग करें।"
लेकिन ... मैं कभी इसका इस्तेमाल क्यों करूं? नोट मुझे object उपयोग के लिए कभी भी आवश्यकता नहीं है, लेकिन मैं समझता हूं कि इसके लिए क्या है।

या तो एक वेबसाइट या डेस्कटॉप एप्लिकेशन का निर्माण करने में कुछ वास्तविक परिस्थितियां क्या हैं, जहां एक DI का उपयोग करेगा? मैं आसानी से मामलों के साथ आ सकता हूं कि किसी को गेम में इंटरफेस / आभासी कार्यों का उपयोग क्यों करना है, लेकिन यह गैर-गेम कोड में उपयोग करने के लिए अत्यंत दुर्लभ (दुर्लभ पर्याप्त है कि मुझे एक उदाहरण याद नहीं) हो सकता है



Answers


सबसे पहले, मैं इस उत्तर के लिए एक धारणा को समझाता हूं। यह हमेशा सच नहीं है, लेकिन अक्सर:

इंटरफेस विशेषण हैं; वर्ग संज्ञाएं हैं

(वास्तव में, वहाँ इंटरफेस हैं जो नाम भी हैं, लेकिन मैं यहाँ सामान्यीकरण करना चाहता हूं।)

इसलिए, उदाहरण के लिए एक इंटरफ़ेस कुछ ऐसे हो सकता है जैसे कि IDisposable , IEnumerable या IPrintable । एक वर्ग इनमें से एक या अधिक इंटरफेस का वास्तविक क्रियान्वयन है: List या Map दोनों IEnumerable कार्यान्वयन हो सकते हैं

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

अब तक सब ठीक है.

आप इस निर्भरता को निम्न Database साथ अपने Database वर्ग के अंदर मॉडल बना सकते हैं:

var logger = new Logger();

और सबकुछ ठीक है यह उस दिन तक ठीक होता है जब आपको पता चलता है कि आपको लॉगर की एक गुच्छा की आवश्यकता है: कभी-कभी आप कंसोल में लॉग इन करना चाहते हैं, कभी-कभी फ़ाइल सिस्टम में, कभी-कभी टीसीपी / आईपी और दूरस्थ लॉगिंग सर्वर का उपयोग करते हुए, और इसी तरह ...

और निश्चित रूप से आप अपने सभी कोड को बदलना नहीं चाहते हैं (इस बीच आपके पास इसके गिजिल हैं) और सभी लाइनों की जगह

var logger = new Logger();

द्वारा:

var logger = new TcpLogger();

सबसे पहले, यह कोई मज़ा नहीं है दूसरा, यह त्रुटि प्रवण है। तीसरा, यह एक प्रशिक्षित बंदर के लिए बेवकूफ़, दोहरावदार काम है। तो तुम क्या करते हो?

जाहिर है यह एक बहुत अच्छा विचार है कि इंटरफेस ICanLog (या समान) को लागू करना है जो सभी विभिन्न ICanLog द्वारा कार्यान्वित किया गया है। तो अपने कोड में चरण 1 यह है कि आप ऐसा करते हैं:

ICanLog logger = new Logger();

अब प्रकार का अनुमान किसी और प्रकार को बदल नहीं सकता है, आपके पास हमेशा एक एकल इंटरफ़ेस है जो कि इसके खिलाफ विकसित होता है। अगले चरण यह है कि आप new Logger() को बार-बार ओवर करना नहीं चाहते हैं तो आप एकल, केंद्रीय कारखाने वर्ग के लिए नए उदाहरण बनाने के लिए विश्वसनीयता डालते हैं, और आपको कोड प्राप्त होता है जैसे:

ICanLog logger = LoggerFactory.Create();

फैक्ट्री खुद तय करता है कि किस तरह का लकड़हारा बनाने के लिए। आपका कोड अब परवाह नहीं करता, और यदि आप इस्तेमाल करने वाले लॉगर का प्रकार बदलना चाहते हैं, तो आप इसे एक बार बदल सकते हैं: फ़ैक्टरी के अंदर।

अब, ज़ाहिर है, आप इस फैक्ट्री को सामान्य बना सकते हैं, और इसे किसी भी प्रकार के लिए काम कर सकते हैं:

ICanLog logger = TypeFactory.Create<ICanLog>();

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

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

और अब, जब आप नामों को थोड़ा बदलते हैं, तो आप एक सर्विस लोकेटर के सरल क्रियान्वयन के साथ समाप्त होते हैं, जो नियंत्रण के उलटाव के दो पैटर्नों में से एक है (चूंकि आप इन्हें नियंत्रित करते हैं कि कौन कौन से सटीक वर्ग को इन्स्तांत करने का फैसला करता है)

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

निर्भरता इंजेक्शन अब इस पंक्ति में अगला कदम है: सर्विस लोकेटर पर इस एकल निर्भरता से छुटकारा पाएं: विशिष्ट इंटरफ़ेस के लिए कार्यान्वयन के लिए सर्विस लोकेटर से पूछे जाने वाले विभिन्न वर्गों के बजाय, आप - एक बार फिर - नियंत्रण कौन करेगा ।

निर्भरता इंजेक्शन के साथ, आपके Database क्लास के पास अभी एक कन्स्ट्रक्टर है जिसके लिए पैरामीटर प्रकार ICanLog की आवश्यकता होती है:

public Database(ICanLog logger) { ... }

अब आपके डेटाबेस में हमेशा उपयोग करने के लिए एक लकड़हारा है, लेकिन यह किसी भी अधिक जानकारी नहीं है जहां यह लॉगर आता है।

और यह वह जगह है जहां एक डि फ्रेमवर्क खेलने में आता है: आप एक बार फिर अपने मैपिंग को कॉन्फ़िगर करते हैं, और उसके बाद अपने डि फ्रेमवर्क से अपने आवेदन को इन्स्टिट्यूट के लिए पूछें। के रूप में Application वर्ग के लिए एक ICanPersistData कार्यान्वयन की आवश्यकता है, Database का एक उदाहरण इंजेक्शन है - लेकिन इसके लिए उसे पहले ICanLog लिए कॉन्फ़िगर किया गया लॉगर के प्रकार का एक उदाहरण बनाना होगा और इसी तरह ...

इसलिए, एक लंबी कहानी कम करने के लिए: निर्भरता इंजेक्शन आपके कोड में निर्भरता को हटाने के दो तरीकों में से एक है। संकलन-समय के बाद विन्यास परिवर्तनों के लिए यह बहुत उपयोगी है, और यह इकाई परीक्षण के लिए एक बढ़िया चीज है (क्योंकि यह स्टब्स और / या मोजे को इंजेक्ट करना बहुत आसान बनाता है)

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

लेकिन मूल रूप से, यह है

उम्मीद है की वो मदद करदे।

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




मुझे लगता है कि कई बार लोग निर्भरता इंजेक्शन और निर्भरता इंजेक्शन ढांचे (या एक कंटेनर के रूप में अक्सर कहा जाता है) के बीच के अंतर के बारे में भ्रमित हो जाते हैं।

निर्भरता इंजेक्शन एक बहुत सरल अवधारणा है इस कोड के बजाय:

public class A {
  private B b;

  public A() {
    this.b = new B(); // A *depends on* B
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  A a = new A();
  a.DoSomeStuff();
}

आप इस तरह कोड लिखते हैं:

public class A {
  private B b;

  public A(B b) { // A now takes its dependencies as arguments
    this.b = b; // look ma, no "new"!
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  B b = new B(); // B is constructed here instead
  A a = new A(b);
  a.DoSomeStuff();
}

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

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




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

आईओसी सिद्धांत है, जहां DI पैटर्न है कारण यह है कि आपको "एक से अधिक लॉगगर की आवश्यकता" संभवतः कभी नहीं मिले, जब तक मेरा अनुभव चला जाता है, लेकिन वास्तविक कारण यह है कि आपको वास्तव में इसकी आवश्यकता है, जब भी आप कुछ का परीक्षण करते हैं एक उदाहरण:

मेरा फ़ीचर:

जब मैं एक ऑफ़र पर गौर करता हूं, तो मुझे यह चिन्ह देना चाहिए कि मैंने इसे स्वचालित रूप से देखा, ताकि मैं ऐसा करने के लिए नहीं भूल सकता।

आप इस तरह से यह परीक्षण कर सकते हैं:

[Test]
public void ShouldUpdateTimeStamp
{
    // Arrange
    var formdata = { . . . }

    // System under Test
    var weasel = new OfferWeasel();

    // Act
    var offer = weasel.Create(formdata)

    // Assert
    offer.LastUpdated.Should().Be(new DateTime(2013,01,13,13,01,0,0));
}

तो कहीं OfferWeasel , यह आपको इस तरह एक प्रस्ताव ऑब्जेक्ट बनाता है:

public class OfferWeasel
{
    public Offer Create(Formdata formdata)
    {
        var offer = new Offer();
        offer.LastUpdated = DateTime.Now;
        return offer;
    }
}

यहां समस्या यह है कि यह परीक्षण सबसे असफल होगा, क्योंकि जिस तिथि को सेट किया जा रहा है, उस तारीख से अलग होगा, भले ही आप DateTime.Now को भी डाल दें। अब परीक्षण कोड में यह कुछ मिलीसेकेंड से बंद हो सकता है और इसलिए हमेशा असफल रहेगा। एक बेहतर समाधान अब इसके लिए एक इंटरफ़ेस बनाना होगा, जो आपको समय निर्धारित करने की अनुमति देता है:

public interface IGotTheTime
{
    DateTime Now {get;}
}

public class CannedTime : IGotTheTime
{
    public DateTime Now {get; set;}
}

public class ActualTime : IGotTheTime
{
    public DateTime Now {get { return DateTime.Now; }}
}

public class OfferWeasel
{
    private readonly IGotTheTime _time;

    public OfferWeasel(IGotTheTime time)
    {
        _time = time;
    }

    public Offer Create(Formdata formdata)
    {
        var offer = new Offer();
        offer.LastUpdated = _time.Now;
        return offer;
    }
}

अंतरफलक अमूर्त है एक असली बात है, और दूसरा एक आपको कुछ समय के लिए नकली बनाने की अनुमति देता है जहां यह आवश्यक है। इस परीक्षण को फिर से बदल दिया जा सकता है:

[Test]
public void ShouldUpdateTimeStamp
{
    // Arrange
    var date = new DateTime(2013, 01, 13, 13, 01, 0, 0);
    var formdata = { . . . }

    var time = new CannedTime { Now = date };

    // System under test
    var weasel= new OfferWeasel(time);

    // Act
    var offer = weasel.Create(formdata)

    // Assert
    offer.LastUpdated.Should().Be(date);
}

इस तरह, आप निर्भरता (वर्तमान समय प्राप्त करने) के लिए इंजेक्शन लगाने के द्वारा "नियंत्रण का उलटा" सिद्धांत लागू करते हैं। ऐसा करने का मुख्य कारण आसान पृथक इकाई परीक्षण के लिए है, ऐसा करने के अन्य तरीके हैं उदाहरण के लिए, यहां एक इंटरफ़ेस और एक वर्ग अनावश्यक है क्योंकि सी # फ़ंक्शंस में वेरिएबल्स के रूप में पास किया जा सकता है, इसलिए एक इंटरफ़ेस के बजाय आप Func<DateTime> का उपयोग करके एक ही प्राप्त कर सकते हैं। या, यदि आप एक गतिशील दृष्टिकोण लेते हैं, तो आप किसी भी ऑब्जेक्ट को पास करते हैं, जिसकी समकक्ष विधि ( बतख टंकण ) है, और आपको बिल्कुल इंटरफ़ेस की ज़रूरत नहीं है।

आपको शायद ही कभी एक से अधिक लॉगगर की आवश्यकता होगी इसके बावजूद, स्थिरता टाइप किए गए कोड जैसे जावा या सी # के लिए निर्भरता इंजेक्शन आवश्यक है।

और ... यह भी ध्यान दिया जाना चाहिए कि एक ऑब्जेक्ट रनटाइम पर केवल उसके उद्देश्य को ठीक से पूरा कर सकता है, अगर उसकी निर्भरता उपलब्ध है, तो संपत्ति इंजेक्शन की स्थापना में बहुत अधिक उपयोग नहीं है। मेरे विचार में, सभी निर्भरता को संतुष्ट किया जाना चाहिए जब कन्स्ट्रक्टर को बुलाया जा रहा है, इसलिए कन्स्ट्रक्टर-इंजेक्शन एक साथ जाने की बात है।

मुझे आशा है कि मदद की




मुझे लगता है कि क्लासिक जवाब एक और डिकॉप्ल्ड एप्लिकेशन बनाना है, जिसके पास कोई ज्ञान नहीं है, जो कि रनटाइम के दौरान क्रियान्वयन का उपयोग किया जाएगा।

उदाहरण के लिए, हम एक केंद्रीय भुगतान प्रदाता हैं, जो दुनिया भर के कई भुगतान प्रदाताओं के साथ काम कर रहे हैं। हालांकि, जब कोई अनुरोध किया जाता है, मुझे नहीं पता कि कौन से भुगतान प्रोसेसर मैं कॉल करने जा रहा हूं। मैं स्विच मामलों के एक टन के साथ एक वर्ग को प्रोग्राम कर सकता हूं, जैसे:

class PaymentProcessor{

    private String type;

    public PaymentProcessor(String type){
        this.type = type;
    }

    public void authorize(){
        if (type.equals(Consts.PAYPAL)){
            // Do this;
        }
        else if(type.equals(Consts.OTHER_PROCESSOR)){
            // Do that;
        }
    }
}

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

class PaypalProcessor implements PaymentProcessor{

    public void authorize(){
        // Do PayPal authorization
    }
}

class OtherProcessor implements PaymentProcessor{

    public void authorize(){
        // Do other processor authorization
    }
}

class PaymentFactory{

    public static PaymentProcessor create(String type){

        switch(type){
            case Consts.PAYPAL;
                return new PaypalProcessor();

            case Consts.OTHER_PROCESSOR;
                return new OtherProcessor();
        }
    }
}

interface PaymentProcessor{
    void authorize();
}

** कोड संकलित नहीं होगा, मुझे पता है :)




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

यह लंबे समय तक ओओपी में पहले से ही सामान्य है कई बार कोड टुकड़े बनाने जैसे:

I_Dosomething x = new Impl_Dosomething();

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

I_Dosomething x = ServiceLocator.returnDoing(String pKey);

DI उदाहरण:

I_Dosomething x = DIContainer.returnThat();

DI की आवश्यकताओं में से एक यह है कि कंटेनर को पता लगाना चाहिए कि किस इंटरफ़ेस का कार्यान्वयन है। इसलिए एक डि कंटेनर को एक ही समय में प्रत्येक इंटरफ़ेस के लिए दृढ़ता से टाइप किए गए डिज़ाइन और केवल एक कार्यान्वयन की आवश्यकता होती है। यदि आपको एक ही समय में एक इंटरफ़ेस के अधिक कार्यान्वयन की आवश्यकता है (जैसे कैलकुलेटर), तो आपको सेवा लोकेटर या फ़ैक्टरी डिज़ाइन पैटर्न की आवश्यकता है।

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

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