2016-06-21 13 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); 
     } 
    } 
} 

这现在是最好的/清洁/更少的邪恶/更少具体/抽象/无论我能弄清楚的解决方案。欢迎任何评论。