2016-06-21 41 views
0

所以我有這個應用程序,即使用IOC(autofac)。同時,我發現自己處於需要工廠的位置。在工廠內部,我創建了具有依賴性的新對象 - 所以現在我想知道,我怎麼能結婚呢?工廠和國際石油公司一起 - 如何使用兩者?

public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory 
{ 
    public ISubscriptionHandler GetProvider(StreamType streamType) 
    { 
     switch (streamType) 
     { 
      case StreamType.Rss: 
       return new RssSubscriptionHandler(null,null,null,null); 
      case StreamType.Person: 
       return new PersonSubscriptionHandler(null, null, null, null); 
      default: 
       throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null); 
     } 
    } 
} 
+1

注入的IoC容器進工廠,然後使用暴露的方法來獲取所需的具體類型的實例。然後容器將爲您解析其他依賴關係。 –

+0

@MartinCostello這是一個服務定位器,很大程度上被認爲是反模式,即使在工廠內完成。 –

+0

你確定你需要一個工廠嗎?爲什麼你確定你不能讓IoC容器爲你構建對象依賴關係圖? –

回答

1

你可以使用named and keyed service和使用IIndex<TKey, TService>

註冊看起來是這樣的檢索實例:

builder.RegisterType<RssHandler>().Keyed<ISubscriptionHandler>(StreamType.Rss); 
builder.RegisterType<PersonHandler>().Keyed<ISubscriptionHandler>(StreamType.Person); 
builder.RegisterType<SubscriptionHandlerFactory>().As<ISubscriptionHandlerFactory>(); 

和工廠這樣的:

public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory 
{ 
    public SubscriptionHandlerFactory(IIndex<StreamType, ISubscriptionHandler> handlers) 
    { 
     this._handlers = handlers; 
    } 

    private readonly IIndex<StreamType, ISubscriptionHandler> _handlers; 

    public ISubscriptionHandler GetProvider(StreamType streamType) 
    { 
     return this._handlers[streamType]; 
    } 
} 
+0

這太棒了。爲了不依賴於autofac,我也可以抽象出IIndex。 – jstadnicki

+0

實際上,該工廠剛剛成爲autofac的抽象,從該工廠客戶的角度來看 - 這更好! – jstadnicki

0

您不能使用IoC來永遠抽象出對象的實例。在某些時候,你將不得不創建一個具體的實例(在你的工廠或你的IoC容器中)

你可以將autofac容器注入你的工廠,或者由於你的工廠本身實現了一個接口,你的工廠的不同版本到什麼類別可能需要它們(例如,如果你需要一個不同的工廠進行單元測試)

0

我解決了它。有點。由於我不想依賴Autofac,所以我自己被撕裂了。但是,感謝@ martin-costello,在我看來,也許我不需要採用autofac,但是IDependencyResolver中的構建並不那麼邪惡。由於我無法將autofac註冊爲IDependencyResolver,因此我將DependencyResolver註冊爲IDependencyResolver。再向前一步。由於註冊發生在autofac DependencyResolver.SetResolver發生之前,我需要使用Lazy,它最終解決了我的問題。

這裏的代碼(或至少是最好的解決辦法,我發現)

// other registration 
builder.RegisterType<RssSubscriptionHandler>(); 
builder.RegisterType<PersonSubscriptionHandler>(); 
// even more registration here 

builder.RegisterType<SubscriptionHandlerFactory>() 
     .As<ISubscriptionHandlerFactory>() 
     .WithParameter(new TypedParameter(typeof(Lazy<IDependencyResolver>), 
         new Lazy<IDependencyResolver>(() => DependencyResolver.Current))); 

然後工廠修改本(前清理):

public class SubscriptionHandlerFactory : ISubscriptionHandlerFactory 
{ 
    private readonly Lazy<IDependencyResolver> resolver; 

    public SubscriptionHandlerFactory(Lazy<IDependencyResolver> resolver) 
    { 
     this.resolver = resolver; 
    } 

    public ISubscriptionHandler GetProvider(StreamType streamType) 
    { 
     switch (streamType) 
     { 
      case StreamType.Rss: 
       return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(RssSubscriptionHandler)); 
      case StreamType.Person: 
       return (ISubscriptionHandler)this.resolver.Value.GetService(typeof(PersonSubscriptionHandler)); 
      default: 
       throw new ArgumentOutOfRangeException(nameof(streamType), streamType, null); 
     } 
    } 
} 

這現在是最好的/清潔/更少的邪惡/更少具體/抽象/無論我能弄清楚的解決方案。歡迎任何評論。