2012-02-02 13 views
5

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

मैं निम्नलिखित कारखाने वर्ग जो archiveReader.GetArchiveType() साथ संग्रह के पहले कुछ बाइट्स पढ़कर ArchiveType निर्धारित करता है पर देख रहा हूँ और फिर ArchiveType enum के आधार पर एक ArchiveRestorer का एक उदाहरण देता है।

public class ArchiveRestorerFactory : IArchiveRestorerFactory 
{ 
    public ArchiveRestorer Create(ArchiveReader archiveReader) 
    { 
     ArchiveType type = archiveReader.GetArchiveType(); 
     switch (type) 
     { 
      case ArchiveType.CurrentData: 
       return new CurrentDataArchiveRestorer(archiveReader); 
       break; 
      case ArchiveType.HistoricalData: 
       return new HistoricalDataArchiveRestorer(archiveReader); 
       break; 
      case ArchiveType.AuditTrail: 
       return new AuditTrailArchiveRestorer(archiveReader); 
       break; 
      default: 
       throw new Exception("ArchiveRestorerFactory error: Unknown value for ArchiveType."); 
     } 
    } 
} 

मैं यह कैसे refactor है ताकि वर्ग ठोस प्रकार CurrentDataArchiveRestorer, HistoricalDataArchiveRestorer और AuditTrailArchiveRestorer पर निर्भर नहीं करता?

क्या मुझे तीन ठोस पुनर्स्थापकों को कारखाने के निर्माता में स्थानांतरित करना चाहिए?

public ArchiveRestorer Create(ArchiveReader archiveReader, 
    ArchiveRestorer currentDataArchiveRestorer, 
    ArchiveRestorer historicalDataArchiveRestorer, 
    ArchiveRestorer auditTrailDataArchiveRestorer) 
{ 
    // guard clauses... 
    // assign to readonly fields 
} 

दृष्टिकोण प्रतीत हो रहा है कि सुझाव दिया here, लेकिन तब यह जब केवल एक की जरूरत है सभी तीन संरक्षणकर्ताओं का दृष्टांत होगा? क्या होगा यदि मेरे पास 20 अलग-अलग संभावित ठोस कार्यान्वयन हों?

मुझे लगता है कि मुझे प्रत्येक प्रकार के पुनर्स्थापक के लिए एक ठोस कारखाना लागू करना चाहिए और इसके बदले में लौटना चाहिए, लेकिन फिर मैं एक new को दूसरे के साथ बदल दूंगा।

इस पर प्रतिक्रिया करने का सबसे अच्छा तरीका क्या है?

+1

मुझे लगता है कि आपका परिदृश्य जिम्मेदारी पैटर्न की श्रृंखला के लिए बेहतर अनुकूल हो सकता है। एक विशिष्ट डी कंटेनर (एकता) के संयोजन के साथ पैटर्न के उपयोग के लिए [इस उदाहरण] (http://davidhayden.com/blog/dave/archive/2008/11/19/ChainResponsibilityDesignPatternUnityDependencyInjectionContainer.aspx) को देखें। –

+0

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

+0

'अनावश्यक') के अलावा 'enum'' के उपयोग के अलावा, विशेष रूप से आपके वर्तमान कार्यान्वयन के बारे में आपको क्या परेशानी होती है? –

उत्तर

2

जिस तरह से मैं यह करूँगा, आपको जो कोड मिला है, उसे दिया गया है, इन वस्तुओं में से प्रत्येक के लिए एक कारखाना बनाना होगा जिसमें Create() विधि हो।

मेरे पास इन कारखानों के लिए भी एक इंटरफेस होगा और उन्हें एक सामान्य फैक्टरी इंटरफ़ेस से प्राप्त होगा।

फिर आप अपने कन्स्ट्रक्टर में इंजेक्शन के लिए इंटरफेस का उपयोग कर सकते हैं।

कौन इस के समान ही कहा जाता है:

case ArchiveType.CurrentData: 
       return _currentDateArchiveRestorerFactory.Create(archiveReader); 
       break; 

वैकल्पिक रूप से, यह बेहतर हो सकता है एक भी कारखाना है कि किसी भी प्रकार का एक उदाहरण बनाता है। चूंकि ये सभी ऑब्जेक्ट पुनर्स्थापक हैं, इसलिए आप के आधार पर switch के बजाय केवल उदाहरण बना सकते हैं।

_restorerFactory.Create(ArchiveType.CurrentData); 
1

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

0
interface ILogger 
{ 
    void Log(string data); 
} 

class Logger : ILogger 
{ 
    . 
    . 
    . 
} 

इस बिंदु पर, आप लकड़हारा वापस जाने के लिए घटक के भीतर प्रयोग की जाने वाली एक मध्यवर्ती कारखाने वस्तु का उपयोग करें:

class MyComponent 
{ 
    void DoSomeWork() 
    { 
    // Get an instance of the logger 
    ILogger logger = Helpers.GetLogger(); 
    // Get data to log 
    string data = GetData(); 

    // Log 
    logger.Log(data); 
    } 
} 

class Helpers 
{ 
    public static ILogger GetLogger() 
    { 
    // Here, use any sophisticated logic you like 
    // to determine the right logger to instantiate. 

    ILogger logger = null; 
    if (UseDatabaseLogger) 
    { 
     logger = new DatabaseLogger(); 
    } 
    else 
    { 
     logger = new FileLogger(); 
    } 
    return logger; 
    } 
} 
class FileLogger : ILogger 
{ 
    . 
    . 
    . 
} 

class DatabaseLogger : ILogger 
{ 
    . 
    . 
    . 
} 
2

क्यों उचित ArchiveRestorer बनाने के लिए ArchiveReader जिम्मेदार नहीं है?तो कोड के पहले यात्रा इस प्रकार दिखाई देगा:

public class ArchiveRestorerFactory : IArchiveRestorerFactory 
{ 
    public ArchiveRestorer Create(ArchiveReader archiveReader) 
    { 
     ArchiveRestorer restorer = archiveReader.GetArchiveRestorer(); 
     return restorer; 
    } 
} 

तब तक, यह बहुत स्पष्ट है कि कारखाने, निरर्थक है तो कोड के दूसरे चरण में आप फेंक कर सकते हैं इसे दूर उपभोक्ताओं आह्वान करते होना चाहिए सीधे ArchiveReader।

+0

यह एक उत्कृष्ट रिफैक्टरिंग की तरह लगता है और मैं इसे लागू कर दूंगा, लेकिन यह निर्भरता समस्या का समाधान नहीं करता है। यह निर्भरता को 'ArchiveReader' वर्ग में ले जाता है। 'ArchiveReader.GetArchiveRestorer() 'को अभी भी' ArchiveRestorer' के सही उप-वर्ग को' नया 'करने की आवश्यकता होगी। – shamp00

+1

उन्हें ArchiveReader में इंजेक्ट करें। यह सब ठीक उपप्रकार का चयन करने के तरीके के लिए उबाल जाता है। चूंकि आपने इसे साझा नहीं किया है, इसलिए जवाब देने में थोड़ा मुश्किल है। हालांकि, अगर आप इसे साझा करने का निर्णय लेते हैं, तो यह SO पर एक नया प्रश्न होना चाहिए। –

+0

क्या यह दोनों निर्भरता समस्या को हल करने में विफल नहीं हैं (जैसा उपरोक्त टिप्पणी में उल्लिखित है) और एसआरपी भी तोड़ता है? मैं वर्तमान में आपकी पुस्तक पढ़ रहा हूं लेकिन वास्तविक कोड में सिद्धांतों को लागू करने का प्रयास करते समय इन चीजों के साथ पकड़ा जा रहा हूं। – Steve

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