與DI

2013-04-11 94 views
19

一個接口多個實現現在,我想教自己與Autofac的IOC容器的依賴注入模式。我提出了一個非常簡單的例子,下面將介紹這個例子。雖然這個例子很簡單,但我無法正常工作。與DI

這裏是我的類/接口:

兩個怪物,既實現IMonster接口:

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!"); 
    } 
} 

再有就是我的墓地:

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(); 
    } 
} 

最後我主:

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。

有沒有一種簡單的方法來解決這一問題? 還是我的Autofac工作方式完全錯誤? 你會如何解決這個問題?

+1

我想你可能正在尋找[Named Services](https://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices)。 – 2013-04-11 08:09:29

+0

autofac如何解析Graveyard類的兩個構造函數參數? – MattDavey 2013-04-11 08:11:41

+1

MattDavey有一個正確的答案。似乎解析器無法找到兩個構造函數的Func 和Func 的特定內容,因此替換爲null。也許註冊這兩個func到解析器都可以解決問題 – Fendy 2013-04-11 08:15:17

回答

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(); 
    } 
} 

如果你願意,當然可以使用特定的怪物工廠了。無論如何,使用接口將使你的代碼更具可讀性。

更新

但我會如何實現工廠?一方面,工廠不應使用IOC容器創造的怪物,因爲這是認爲是邪惡的(降低了DI模式服務定位器反模式)。

我很厭倦聽到SL是反模式。不是。與所有模式一樣,如果使用不當,它會給您帶來不便。這適用於所有模式。 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); 
    } 
} 

這並不比這更復雜。

在另一方面,工廠不應創建怪物本身,因爲這將繞過IOC容器和緊密結合工廠和怪物。或者我又在錯誤的軌道上? ;-)

工廠與怪物實施緊密結合並不重要。因爲這就是工廠的目的:要抽象出對象的創建,以便代碼中的其他任何內容都不會意識到這些混凝土。

您可以創建SuperDeluxeMonsterFactory,MonstersForCheapNonPayingUsersFactory等。應用程序中的所有其他代碼不會意識到您正在使用不同的怪物(通過使用不同的工廠)。

每次需要更換混凝土時,您可以切換工廠,也可以修改現有工廠。只要你的怪物實現不違反Liskovs替換原則,其他代碼就不會受到影響。

廠VS IoC容器

那麼什麼是工廠和IoC容器,然後有什麼區別? IoC非常適合爲您的類解析依賴關係並維護生命週期(例如,容器可以在HTTP請求結束時自動處理所有一次性使用的對象)。

另一方面,工廠擅長爲您創建對象。它做到了,沒有別的。

摘要

所以,如果你的地方在你的代碼需要得到一個特定的類型,你通常應該使用一個工廠實現的。工廠本身可以在內部使用IoC作爲服務定位器(以解決依賴關係)。這很好,因爲它是工廠中的一個實現細節,不會影響應用程序中的其他任何內容。

如果你想解析一個服務(並且不關心你得到的實現,或者如果你得到一個以前創建的實例),使用IoC容器(通過依賴注入)。

+0

但是我將如何實現工廠?一方面,工廠不應使用IOC容器創造的怪物,因爲這是認爲是邪惡的(降低了DI模式服務定位器反模式)。另一方面,工廠不應該自己製造怪物,因爲那樣會繞過國際奧委會集裝箱,並將工廠和怪物緊密結合在一起。或者我又在錯誤的軌道上? ;-) – Boris 2013-04-11 08:21:07

+0

閱讀我的更新。 – jgauffin 2013-04-11 08:34:46

+0

小LSP描述:http://blog.gauffin.org/2011/05/liskovs-substitution-principle/ – jgauffin 2013-04-11 08:44:37