繁体   English   中英

没有服务定位器的工厂模式

[英]Factory pattern without service locator

我目前只能尝试编写不依赖服务位置的工厂类。

我能想到的唯一其他选择是使用构造函数注入来注入所有可能的实例,但是当类通过引用传递时,这可能会导致意外。 一旦可能的提供商数量增加,它也可能会变得昂贵且混乱。

提供程序本身是完全复杂的类,它们具有自己的依赖关系,因此手动构造无法实现。

更新的服务位置示例:

    public class ProviderFactory : IProviderFactory
    {
        private readonly IProviderConfigurationService _providerConfigurationService;

        public enum SearchType
        {
            Foo,
            Bar
        }

        public ProviderFactory(IProviderConfigurationService providerConfigurationService)
        {
            _providerConfigurationService = providerConfigurationService;
        }

        public Collection<IProvider> GetProviderInstances(SearchType searchType)
        {
            // Provider configuration service will read a XML/DB store to retrieve list of search providers applicable for a search type
            var providerList = _providerConfigurationService.GetProviderList(searchType);
            return new Collection<IProvider>(providerList.ForEach(x=> ServiceLocator.GetInstance(typeof(x))).ToList()) ;
        }
    }

我还有其他选择吗? 我目前正在使用Unity for DI。

一种替代方法是将Func<Type, object>传递给构造函数,并通过您的容器实现该函数:

unity.RegisterInstance<Func<Type, object>>(t => unity.Resolve(t))

然后在您的课程中:

public ProviderFactory(Func<Type, object> createFunc, IProviderConfigurationService pcs)
{
    _createFunc = createFunc; 
}

public Collection<IProvider> GetProviderInstances(SearchType searchType)
{
    var providerList = _providerConfigurationService.GetProviderList(searchType);
    return new Collection<IProvider>(providerList.Select(_createFunc).ToList());
}

您缺少抽象。

您的ProviderFactory应该实现IProviderFactory抽象。 这样,您可以将该接口放置在应用程序的基础库中,并且可以将ProviderFactory实现放置在您的Composition Root中 对于位于合成根目录中的代码,可以引用DI库,在这种情况下, 您无需使用service location

最近,我使用DI框架在自己的代码中解决了一个非常相似的问题。 为了满足Dependency Inversion,工厂构造函数应接受一个接口(如其他答案所述),但是要获取注入正确类型的框架却很棘手,而没有大量详细列出每种可能的构想的参数。

SimpleInjector允许您使用以下命令注册给定抽象的所有具体构想:

Container.RegisterCollection(typeof(IProvider), new [] {typeof(TKnown).Assembly,...});

您的XML可以列出定义了具体对象的(可能是外部的)程序集,您可以从那里建立程序集数组。 然后,您的工厂只需要接受它们并选择一个即可,也许基于您提到的searchType。

public class ProviderFactory
{
    private List<IProvider> providers;
    public ProviderFactory(IEnumerable<IProvider> providers)
    {
        this.providers = providers.ToList();
    }

    public IProvider GetProvider(string searchType)
    {
        // using a switch here would open the factory to modification
        // which would break OCP
        var provider = providers.SingleOrDefault(concretion => concretion.GetType().Name == searchType);

        if (provider == null) throw new Exception("No provider found of that type.  Are you missing an assembly in the RegisterCollection for IProvider?");

        return provider;
    }

我知道我在这方面迟到了,但是假设其他人认为这种方法没有问题,它可能会有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM