2009-09-26 20 views
8

इस सरल उदाहरण पर विचार करें।परिपत्र निर्भरताओं के साथ गुइस का उपयोग

Class A { 
    B b; 
    A() { 
     this.b = new B(this); 
    } 
} 

इस उदाहरण उदाहरण एक में उदाहरण बी के बारे में जानता है, और उदाहरण बी उदाहरण ए के बारे में जानता

मेरा प्रश्न है: कैसे Guice, यानी साथ उदाहरण के एक दृष्टांत को Guice देखभाल करने के लिए कैसे इस जटिल सर्कल निर्भरताओं के?

+0

आप बस ए मैं अपने वास्तविक वर्ग अनुमान लगा रहा हूँ के लिए निर्माता को @Inject जोड़ सकते हैं थोड़ा और अधिक जटिल है। क्या बी इंटरफ़ेस है? क्या ए के अलावा कुछ के साथ इंजेक्शन की आवश्यकता है? बीटीडब्लू, "इस" क्षेत्र को कन्स्ट्रक्टर से बचने देना आम तौर पर एक बुरा विचार है। – NamshubWriter

+0

नहीं, बी एक इंटरफेस नहीं बल्कि एक वर्ग है। बेशक, सर्कल निर्भरताएं अच्छी नहीं हैं और मैं इन दो वर्गों को दोबारा कर सकता हूं, लेकिन मुझे वास्तव में जो चाहिए वह गुइस व्यवहार्यता को समझना है। –

उत्तर

4

अपने पहले प्रश्न का उत्तर देने के लिए "तत्काल कैसे करें Guice के साथ "उदाहरण एक: आप बस निर्माता को @Inject जोड़ सकते हैं:

class A { 
    private final B b; 

    @Inject 
    A() { 
     this.b = new B(this); 
    } 
} 

यह काम करता है क्योंकि A बनाने के लिए एपीआई एक सर्कुलर निर्भरता नहीं है। गुइस A कन्स्ट्रक्टर का उपयोग करेगा जब भी इसे A ऑब्जेक्ट बनाने या इंजेक्ट करने की आवश्यकता होगी।

यदि आपका प्रश्न यह है कि ऑब्जेक्ट बनाने के लिए एआईपी बनाने के लिए गुइस का उपयोग कैसे किया जाए, जहां ऑब्जेक्ट बनाने के लिए एपीआई में गोलाकार निर्भरता है, तो this blog post by Misko Hevery (जैसा कि यूरी के उत्तर में उल्लिखित है) देखें।

+2

आपको नो-Args कन्स्ट्रक्टर के लिए @ इंजेक्ट की भी आवश्यकता नहीं है। – ColinD

+0

यह यरी के समान कोड है। @ इंजेक्ट का कोई प्रभाव नहीं पड़ता है और कोड बी से ए को दोगुना नहीं करता है, जो कि गुइस का पूरा बिंदु है। – nes1983

+0

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

4

उत्तर यह है कि आपको अपने कोड में परिपत्र निर्भरता पर निर्भरता इंजेक्शन ढांचे का उपयोग नहीं करना चाहिए।

तो, आपको पहले कोड को दोबारा प्रतिक्रिया देना होगा। जहां तक ​​मुझे पता है, कड़े युग्मित वर्गों के लिए दो समाधान हैं: या तो दो वर्गों को एक में मिलाएं या नई कक्षा शुरू करें और इसमें सामान्य तर्क को स्थानांतरित करें (विस्तार से here देखें)

+4

मुझे लगता है कि आपको बोल्ड भाग को फिर से पढ़ना होगा :) –

+0

युरी के साथ सहमत। डी कारण दर्द के साथ परिपत्र निर्भरता। –

8

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

public interface A { /* skipping methods */ } 
public interface B { /* skipping methods */ } 

public class AImpl implements A { 
    private final B b; 

    @Inject 
    public AImpl(B b) { 
     this.b = b; 
    } 
    // ... 
} 

public class BImpl implements B { 
    private final A a; 

    @Inject 
    public BImpl(A a) { 
     this.a = a; 
    } 
    // ... 
} 

यहां तक ​​कि अगर AImpl और BImpl एकमात्र, Guice इस इंजेक्शन (एक प्रॉक्सी के माध्यम से) संभाल कर सकते हैं के रूप में scoped रहे हैं। यह किसी भी दर पर इस तरह के एक साधारण मामले में काम करता है ... मुझे लगता है कि वहां अधिक जटिल परिपत्र निर्भरताएं हो सकती हैं जो इसे संभाल नहीं सकतीं। वैसे भी, सर्कुलर निर्भरताओं को समाप्त करना निश्चित रूप से बेहतर होगा।

+0

यह वास्तव में केवल सिंगलेट के लिए काम करता है। सामान्य मामले के बारे में क्या? – nes1983

+0

इस इंजेक्शन के दृश्य के पीछे क्या हो रहा है इस पर कोई विचार? –

3

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

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

एक यथार्थवादी परिदृश्य में, आपको पृथक्करण का लाभ उठाने के लिए इंटरफेस के पीछे ए और बी को छिपाने की आवश्यकता होगी।

import com.google.inject.AbstractModule; 
import com.google.inject.Guice; 
import com.google.inject.Inject; 
import com.google.inject.Provider; 
import com.google.inject.assistedinject.Assisted; 
import com.google.inject.assistedinject.FactoryProvider; 

public class Try { 
    public static void main(String[] args) { 
     System.out.println(
       Guice.createInjector(new MyModule()).getInstance(A.class) 
     ); 
    } 
} 

class MyModule extends AbstractModule { 
    public void configure() { 
     bind(A.class).toProvider(AProvider.class); 
     bind(IBFactory.class).toProvider(
       FactoryProvider.newFactory(IBFactory.class, B.class)); 
    } 
} 

class A { 
    B b; 

    public void setB(B b) { 
     this.b = b;  
    } 
} 

class B { 
    A a; 

    @Inject 
    B(@Assisted A a) { 
     this.a = a; 
    } 
} 

class AProvider implements Provider<A> { 

    private final IBFactory bFactory; 

    @Inject 
    AProvider(IBFactory bFactory) { 
     this.bFactory = bFactory; 
    } 

    public A get() { 
     A a = new A(); 
     a.setB(bFactory.create(a)); 
     return a; 
    } 
} 

interface IBFactory { 
    public B create(A a); 
} 

I made an extended version of the circular dependency injection in Guice where A and B are hidden behind interfaces.

संबंधित मुद्दे