[英]Extendable factory design pattern
以下是我的導入工廠類。 如果我想添加新的 ImportTypes,那么只需在 ImportTypes 枚舉中添加新類型並在工廠類中添加一個案例,它就可以正常工作。
我的問題是如何使它更獨立且易於擴展。 假設用戶想要添加一個新的 ImportType 然后他編寫自己的 DLL 並實現接口而不是更改代碼...有什么好的建議/想法嗎?
導入類型
enum ImportTypes
{
DefaultImport,
C2CImport
}
導入接口
public interface IImportService
{
void Import(Argument arguments, ImportDefinition config);
}
進口工廠
class ImportFactory
{
public static IImportService GetService(ImportTypes type)
{
switch (type)
{
case ImportTypes.DefaultImport:
return new DefaultImportService();
case ImportTypes.C2CImport:
return new C2CImportService();
}
return null;
}
}
測試
IImportService docImportService = ImportFactory.GetService(ImportTypes.DefaultImport);
為此,您需要支持在運行時注冊新服務。 因此,您不能使用enum
,因為這些服務是事先未知的; 它們需要通過例如字符串來引用:
class ImportServiceHandler
{
private readonly Dictionary<string, Type> _importServices =
new Dictionary<string, Type>();
public ImportServiceHandler()
{
RegisterService("DefaultImport", typeof(DefaultImportService));
RegisterService("C2CImport", typeof(C2CImportService));
}
public void RegisterService(string name, Type serviceType)
{
if (!serviceType.IsAssignableFrom(typeof(IImportService)))
{
throw new ArgumentException("Type specified doesn't implement IImportService", nameof(serviceType));
}
_importServices.Add(name, serviceType);
}
public IImportService GetService(string name)
{
if (_importServices.ContainsKey(name))
{
return (IImportService)Activator.CreateInstance(_importServices[name]);
}
return null;
}
}
這是一種方法...
在您的 switch 語句中,“默認”將處理任何無法識別的類型。 該類型將在您的程序配置中查找。 用戶必須將他們的類型和路徑添加到實現該類型的程序集。 他們需要實現你的接口。 然后默認情況會加載程序集並實例化對象並將其返回給您。
您將使用 AppDomain.CurrentDomain.Load() 加載程序集。 您將使用 {Assembly}.CreateInstance() 來實例化您的對象。
class ImportFactory
{
public static IImportService GetService(ImportTypes type)
{
switch (type)
{
case ImportTypes.DefaultImport:
return new DefaultImportService();
case ImportTypes.C2CImport:
return new C2CImportService();
default:
return CustomImportService(type);
}
return null;
}
}
CustomImportService 看起來像這樣......
IImportService CustomImportService(ImportTypes type)
{
var assmBytes = GetAssemblyIDByType(type); // you would implement this based on your configuration approach
var assm = AppDomain.CurrentDomain.Load(assmBytes);
var obj = (IImportService)assm.CreateInstance("IImportService");
return obj;
}
這當然只是一個開始,需要努力。
您可以使用原型模式。
創建一個在運行時接收導入類型的類,並返回這些對象的克隆。
它將允許您在運行時加載 ImportTypes,並且不需要更改工廠類。
http://www.dofactory.com/net/prototype-design-pattern
這個鏈接顯示了這個想法。
你可以有這樣的東西:(為清楚起見省略了錯誤處理)
public class Factory {
//store how different objects are created
private IDictionary<string, Func<IImportService>> mappings = new Dictionary<string, Func<IImportService>>()
public void Register(string key, Func<IImportService> expression)
{
mappings[key] = expression;
}
public IImportService GetService(string key)
{
return mappings[key]();
}
}
這可以按以下方式使用:
factory.Register("service", () => new MyCustomImportService());
如果您在編譯時知道所需的類型,則可以提供在簽名中采用該類型的覆蓋。 即Register<MyCustomImportService>(...)
和GetService<MyCustomImportService>
。 在這一點上,考慮是否需要一些輕量級的 IoC 容器可能會很有用
我很想知道當您使用枚舉來決定要返回哪個實現時,如何制作可擴展的工廠模式。 這意味着每次有人用新的實現邏輯構建一個新的 DLL 時,您都必須重構原始代碼(也許這是一個苛刻的描述,因為您所做的只是添加一個新的枚舉元素),並重新構建它。 這有點違背了目的。
我強烈建議不要這樣做。 事實上,我看不出工廠模式如何被認為非常適合您想要做的事情,這更符合可插拔框架的路線,該框架只知道它必須按照要求返回IImportService
實現調用代碼。
這種應用程序設計確實需要一種基於依賴注入的方法。 也許像MEF
東西? 您可以通過像這樣定義依賴項來擺脫困境:
[Export("C2CImport", typeof(IImportService))]
public class C2CImportService : IImportService
除了[Import]
將依賴添加到您想要的代碼中,您還可以像這樣手動解析依賴:
myCompositionContainer.GetExports<IImportService>("C2CImport");
( https://msdn.microsoft.com/en-us/library/dd833299(v=vs.110).aspx )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.