2

我目前正试图编写一个不依赖服务位置的工厂类。

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

提供者本身是完全复杂的类,它们有自己的依赖关系,因此手动构建是不可能的。

更新的服务位置示例:

    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 进行 DI。

4

3 回答 3

2

另一种方法是将 a 传递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());
}
于 2013-10-01T05:21:44.090 回答
1

你缺少一个抽象。

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

于 2013-09-26T09:22:30.217 回答
0

我最近使用 DI 框架在我自己的代码中解决了一个非常相似的问题。为了满足依赖倒置,工厂构造函数应该接受一个接口(正如其他答案所说),但是要让框架注入正确的类型是很棘手的,因为没有大量的参数列表来详细说明每个可能的具体情况。

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

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

于 2018-02-26T08:57:07.247 回答