DI

2013-04-11 6 views
19

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

दो राक्षस, दोनों IMonster इंटरफेस को लागू करने:

interface ILocation 
{ 
    void PresentLocalCreeps(); 
} 

class Graveyard : ILocation 
{ 
    Func<int, IMonster> mVampireFactory; 
    Func<string, IMonster> mZombieFactory; 

    public Graveyard(Func<int, IMonster> vampireFactory, Func<string, IMonster> zombieFactory) 
    { 
    mVampireFactory = vampireFactory; 
    mZombieFactory = zombieFactory; 
    } 

    public void PresentLocalCreeps() 
    { 
    var vampire = mVampireFactory.Invoke(300); 
    vampire.IntroduceYourself(); 

    var zombie = mZombieFactory.Invoke("Rob"); 
    zombie.IntroduceYourself(); 
    } 
} 

और अंत में अपने मुख्य:

interface IMonster 
{ 
    void IntroduceYourself(); 
} 

class Vampire : IMonster 
{ 
    public delegate Vampire Factory(int age); 

    int mAge; 

    public Vampire(int age) 
    { 
    mAge = age; 
    } 

    public void IntroduceYourself() 
    { 
    Console.WriteLine("Hi, I'm a " + mAge + " years old vampire!"); 
    } 
} 

class Zombie : IMonster 
{ 
    public delegate Zombie Factory(string name); 

    string mName; 

    public Zombie(string name) 
    { 
    mName = name; 
    } 

    public void IntroduceYourself() 
    { 
    Console.WriteLine("Hi, I'm " + mName + " the zombie!"); 
    } 
} 

फिर मेरे कब्रिस्तान है

यहाँ मेरी कक्षाओं/इंटरफ़ेस हैं

static void Main(string[] args) 
{ 
    // Setup Autofac 
    var builder = new ContainerBuilder(); 
    builder.RegisterType<Graveyard>().As<ILocation>(); 
    builder.RegisterType<Vampire>().As<IMonster>(); 
    builder.RegisterType<Zombie>().As<IMonster>(); 
    var container = builder.Build(); 

    // It's midnight! 
    var location = container.Resolve<ILocation>(); 
    location.PresentLocalCreeps(); 

    // Waiting for dawn to break... 
    Console.ReadLine(); 
    container.Dispose(); 
} 

और यह मेरी समस्या है: रनटाइम के दौरान, Autofac इस लाइन पर एक अपवाद फेंकता है:

var vampire = mVampireFactory.Invoke(300); 

ऐसा लगता है कि वास्तव में mVampireFactory एक ज़ोंबी का दृष्टांत करने की कोशिश कर रहा है। बेशक यह काम नहीं करेगा क्योंकि ज़ोंबी के निर्माता एक int नहीं ले जाएगा।

क्या इसे ठीक करने का कोई आसान तरीका है? या क्या मुझे ऑटोफैक पूरी तरह से गलत तरीके से काम करने का तरीका मिला? आप इस समस्या को कैसे हल करेंगे?

+1

मुझे लगता है कि आप [नाम सेवाएं] की तलाश में हो सकता है (https://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices)। –

+0

ग्रेफार्ड कक्षा में दो कन्स्ट्रक्टर तर्कों को हल करने वाले ऑटोफैक कैसे हैं? – MattDavey

+1

मैटडेवी का सही जवाब है। लगता है कि संकल्पक दोनों को कन्स्ट्रक्टर के लिए Func और Func का विशेष रूप से नहीं मिल सकता है, इस प्रकार शून्य के साथ प्रतिस्थापित करें। शायद रिज़ॉल्वर में दोनों func को पंजीकृत करने से समस्या – Fendy

उत्तर

22

नियंत्रण कंटेनर का आपका उलटा प्रति कारखाना नहीं है। आपका मामला फैक्ट्री पैटर्न के लिए एकदम सही फिट है।

एक नया सार कारखाने जो अपने राक्षसों बनाने के लिए प्रयोग किया जाता है बनाएँ:

public interface IMonsterFactory 
{ 
    Zombie CreateZombie(string name); 
    Vampire CreateVampire(int age); 
} 

और फिर Autofac में इसके कार्यान्वयन के रजिस्टर।

अंत में अपनी कक्षा में कारखाने का उपयोग करें:

class Graveyard : ILocation 
{ 
    IMonsterFactory _monsterFactory; 

    public Graveyard(IMonsterFactory factory) 
    { 
    _monsterFactory = factory; 
    } 

    public void PresentLocalCreeps() 
    { 
    var vampire = _monsterFactory.CreateVampire(300); 
    vampire.IntroduceYourself(); 

    var zombie = _monsterFactory.CreateZombie("Rob"); 
    zombie.IntroduceYourself(); 
    } 
} 

आप निश्चित रूप से विशिष्ट राक्षस कारखानों भी उपयोग कर सकते हैं अगर आप चाहते हैं। कोई भी कम नहीं, इंटरफेस का उपयोग करके आपके कोड को बहुत अधिक पठनीय बना देगा।

अद्यतन

लेकिन मैं कारखाने कैसे लागू होगा? एक ओर कारखाने को राक्षस बनाने के लिए आईओसी कंटेनर का उपयोग नहीं करना चाहिए, क्योंकि इसे बुरा माना जाता है (सेवा लोकेटर विरोधी पैटर्न के लिए डी पैटर्न को कम करता है)।

मैं यह सुनकर बहुत थक गया हूं कि एसएल एक विरोधी पैटर्न है। यह। सभी पैटर्न के साथ, यदि आप इसे गलत तरीके से उपयोग करते हैं तो यह आपको नुकसान पहुंचाएगा। यह सभी पैटर्न के लिए लागू होता है। http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/

लेकिन इस मामले में मुझे नहीं लगता कि आप सीधे अपने कारखाने में कार्यान्वयन क्यों नहीं बना सकते? कारखाने के लिए यही है:

public class PreferZombiesMonsterFactory : IMonsterFactory 
{ 
    public Zombie CreateZombie(string name) 
    { 
     return new SuperAwesomeZombie(name); 
    } 

    public Vampire CreateVampire(int age) 
    { 
     return new BooringVampire(age); 
    } 
} 

यह उससे अधिक जटिल नहीं है।

दूसरी ओर फैक्ट्री को राक्षसों को स्वयं नहीं बनाना चाहिए, क्योंकि यह आईओसी-कंटेनर को बाईपास करेगा और कारखाने और राक्षसों को कसकर जोड़ देगा। या मैं फिर से गलत ट्रैक पर हूँ? ;-)

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

आप SuperDeluxeMonsterFactory, MonstersForCheapNonPayingUsersFactory आदि बना सकते हैं। आपके आवेदन में अन्य सभी कोड इस बात से अवगत नहीं होंगे कि आप विभिन्न राक्षसों (विभिन्न कारखानों का उपयोग करके) का उपयोग कर रहे हैं।

हर बार जब आप है concretes आप या तो स्विच कारखाने को बदलने के लिए या यदि आप बस मौजूदा कारखाने को संशोधित। जब तक आपके राक्षस कार्यान्वयन Liskovs प्रतिस्थापन सिद्धांत का उल्लंघन नहीं करते हैं तब तक कोई अन्य कोड प्रभावित नहीं होगा।

फैक्टरी आईओसी कंटेनर बनाम

तो एक कारखाने और एक आईओसी कंटेनर तो बीच का अंतर क्या है? आईओसी आपकी कक्षाओं के लिए निर्भरताओं को हल करने और जीवनकाल को बनाए रखने के लिए बहुत अच्छा है (उदाहरण के लिए कंटेनर HTTP अनुरोध समाप्त होने पर सभी डिस्पोजेबल को स्वचालित रूप से निपट सकता है) ..

दूसरी तरफ कारखाना आपके लिए वस्तुओं को बनाने में उत्कृष्टता प्राप्त करता है। यह करता है और कुछ भी नहीं।

सारांश

तो आप अपने कोड में कहीं एक कार्यान्वयन आप आमतौर पर एक कारखाने का उपयोग करना चाहिए की एक विशिष्ट प्रकार प्राप्त करने की आवश्यकता है। फैक्ट्री स्वयं आंतरिक रूप से एक सेवा लोकेटर के रूप में आईओसी का उपयोग कर सकती है (निर्भरताओं को हल करने के लिए)। यह ठीक है क्योंकि यह कारखाने में एक कार्यान्वयन विस्तार है जो आपके आवेदन में किसी और चीज को प्रभावित नहीं करता है।

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

+0

समस्या को ठीक कर सकती है लेकिन मैं कारखाने को कैसे कार्यान्वित करूं? एक ओर कारखाने को राक्षस बनाने के लिए आईओसी कंटेनर का उपयोग नहीं करना चाहिए, क्योंकि इसे बुरा माना जाता है (सेवा लोकेटर विरोधी पैटर्न के लिए डी पैटर्न को कम करता है)। दूसरी ओर कारखाने को राक्षसों को स्वयं नहीं बनाना चाहिए, क्योंकि यह आईओसी-कंटेनर को बाईपास करेगा और कारखाने और राक्षसों को कसकर जोड़ देगा। या मैं फिर से गलत ट्रैक पर हूँ? ;-) – Boris

+0

मेरा अपडेट पढ़ें। – jgauffin

+0

एक छोटा सा LSP विवरण: http://blog.gauffin.org/2011/05/liskovs-substitution-principle/ – jgauffin

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