2011-08-26 20 views
8

सोलिड सिद्धांतों के अनुसार एक वर्ग अन्य वर्गों पर निर्भर नहीं हो सकता है, निर्भरताओं को इंजेक्शन देना होगा। यह सरल है:निर्भरता उलटा। ऑब्जेक्ट सृजन

class Foo 
{ 
    public Foo(IBar bar) 
    { 
     this.bar = bar; 
    } 

    private IBar bar; 
} 

interface IBar 
{ 
} 

class Bar: IBar 
{ 
} 

लेकिन क्या होगा अगर मैं चाहता हूँ बार के बनाने के लिए, Ibar पीछे सटीक कार्यान्वयन नहीं जानने में सक्षम होने की मेरी फू वर्ग? मैं 4 समाधान यहाँ के बारे में सोच सकते हैं, लेकिन उन सभी को कमियां है लगता है:

  1. वस्तु के प्रकार के इंजेक्शन लगाने और का उपयोग कर प्रतिबिंब
  2. जेनेरिक्स का उपयोग कर
  3. "सेवा लोकेटर" का उपयोग करने और हल बुला () तरीका।
  4. एक अलग कारखाने वर्ग बनाने और फू में यह इंजेक्शन लगाने:

class Foo 
{ 
    public void DoSmth(IBarCreator barCreator) 
    { 
     var newBar = barCreator.CreateBar(); 
    } 
} 

interface IBarCreator 
{ 
    IBar CreateBar(); 
} 

class BarCreator : IBarCreator 
{ 
    public IBar CreateBar() 
    { 
     return new Bar(); 
    } 
} 

अंतिम मामले प्राकृतिक लगता है, लेकिन BarCreator वर्ग भी से थोड़ा कोड है। तो आप कैसे सोचते हैं, जो सबसे अच्छा है?

+1

विकल्प 4 सही उत्तर है: http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container/1945023#1945023 –

+1

हालांकि, आप फू को इबार क्यों बनाना चाहते हैं? लीकी एब्स्ट्रैक्शन के प्रति सावधान रहें। –

उत्तर

0

मुझे लगता है कि "मैं चाहता हूं कि मेरी फू क्लास बार बनाने में सक्षम हो" एक और नियम खेलने के लिए आता है जो "चिंता का पृथक्करण" है। तो आपको वर्ग निर्माण के कार्य को किसी और चीज़ के लिए प्रतिनिधि देना चाहिए और फू को उस कार्य के बारे में चिंतित नहीं होना चाहिए।

2

यह सब आपके सटीक परिदृश्य और आपकी आवश्यकताओं पर निर्भर करता है।
मुझे लगता है कि सबसे अधिक उपयोग किया जाने वाला दृष्टिकोण है, जैसा कि आपने उल्लेख किया है, factory
यदि आप आईओसी फ्रेमवर्क (जैसे निनजेक्ट, या स्प्रिंट.Net, कैसल विंडसर इत्यादि का उपयोग कर रहे हैं तो here देखें), एक सेवा लोकेटर भी एक व्यवहार्य समाधान है।

3

मुझे इस मामले में Func<IBar> "इंजेक्ट करना" पसंद है। इस तरह:

class Foo 
{ 
    public Foo(Func<IBar> barCreator) 
    { 
     this.bar = barCreator(); 
    } 

    private IBar bar; 
} 

interface IBar 
{ 
} 
2

यदि आपको अनावश्यक फैक्ट्री इंटरफेस में कोई समस्या है, तो आप यहां दो दृष्टिकोण ले सकते हैं।

यह जेनरिक के साथ पुन: प्रयोज्य करें:

interface IFactory<T> 
{ 
T Create(); 
} 

class DefaultConstructorFactory<T> : IFactory<T>, where T: new() 
{ 
public T Create() { return new T();} 
} 

या एक कारखाने के रूप में अज्ञात फ़ंक्शन का उपयोग करें:

public void DoSomething(Func<IBar> barCreator) 
{ 
var newBar = barCreator(); 
//... 
} 
+0

यह वास्तव में काम नहीं करता है? आप 'डिफॉल्ट कॉन्स्ट्रक्टर फैक्टरी ' को 'IFactory ' के रूप में पास नहीं कर सकते – fearofawhackplanet

3

यही तो कारखानों के लिए किए गए थे।

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

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

सुविधा के लिए, कुछ कंटेनर आपको कंटेनर द्वारा उपयोग किए जाने वाले फैक्ट्री को निर्दिष्ट करने की अनुमति देते हैं जब यह किसी घटक का उदाहरण बनाता है। इस मामले में, आपकी कक्षा सीधे IBar पर निर्भर हो सकती है लेकिन जब आपका एक नया उदाहरण चाहिए तो आपका कंटेनर IBarCreator पर कॉल करेगा।उदाहरण के लिए, कैसल विंडसर में UseFactory और UseFactoryMethod विधियां हैं।

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