我正在研究一个需要严格解耦的接口的模块。具体来说,在实例化根对象(数据源)之后,用户只应该通过接口与对象模型进行交互。我有实际的工厂对象(我称之为提供者)来提供实现这些接口的实例,但这使得获取提供者变得笨拙。为此,我在数据源上提供了几种方法:
public class MyDataSource
{
private Dictionary<Type, Type> providerInterfaceMapping = new Dictionary<Type, Type>()
{
{ typeof(IFooProvider), typeof(FooProvider) },
{ typeof(IBarProvider), typeof(BarProvider) },
// And so forth
};
public TProviderInterface GetProvider<TProviderInterface>()
{
try
{
Type impl = providerInterfaceMapping[typeof(TProviderInterface)];
var inst = Activator.CreateInstance(impl);
return (TProviderInterface)inst;
}
catch(KeyNotFoundException ex)
{
throw new NotSupportedException("The requested interface could not be provided.", ex);
}
}
}
我已经动态修改了一些细节以简化(例如,此代码段不包括传递给创建的实现实例的参数)。这是在C#中实现工厂方法的一般方法吗?
答案 0 :(得分:4)
你应该退后一步,询问使用工厂方法是否是一个好主意?在我看来,事实并非如此。
工厂方法存在多个问题,您的示例说明了几个:
我建议您先看一下依赖注入(DI),而不是尝试手动控制依赖关系。每当您的代码需要一个IFooProvider时,请使用Constructor Injection提供它。
答案 1 :(得分:3)
不要重新发明您自己的dependency injection实现,使用现有的库,如Spring.NET或Microsoft Unity应用程序块。
注入依赖项是一个常见的编程问题,您不应该自己解决。有一些不错的轻量级库(我上面提到过几个)可以很好地完成工作。它们支持定义依赖关系的声明性和命令式模型,并且非常擅长于它们的工作。
答案 2 :(得分:1)
从技术上讲,这很好,但是大多数情况下,当我看到工厂时,它通常会返回相同类型的界面,例如IProvider
而不是IFooProvider
或IBarProvider
,这对我来说没有没有意义。如果您要使用FooProvider和BarProvider,那么为什么要为它们提供不同的接口。我会使用一个接口IProvider
并让FooProvider
和BarProvider
实现该接口。
答案 3 :(得分:0)
无论使用工厂方法的正确与否(因为这不是你所问的!),你的实现对我来说很好。
可能比对代码映射进行硬编码更有效的方法是将该信息放入配置文件并将其加载到您的应用程序中。
答案 4 :(得分:0)
为了它的价值,我一直使用这种模式,并将这种逻辑抽象为可重用的程序集。它使用反射,泛型和属性在运行时定位和绑定具体类型。 http://www.codeproject.com/KB/architecture/RuntimeTypeLoader.aspx
这有助于解决Mark的问题,因为实现类型不是硬编码的,而且实现类型由安装决定,而不是在项目程序集引用中确定。