[英]What's the difference between the Service Locator and the Factory Design pattern?
[英]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.