这是一个好的工厂方法实现吗?
我正在开发一个需要严格解耦接口的模块。具体来说,在实例化根对象(数据源)之后,用户只能通过接口与对象模型进行交互。我有实际的工厂对象(我称之为提供程序)来提供实现这些接口的实例,但这使得获取提供程序变得很笨拙。为此,我在数据源上提供了一些方法:
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# 中实现工厂方法的通用方法吗?
I'm working on a module that requires a strictly decoupled interface. Specifically, after instantiating the root object (a datasource), the user's only supposed to interact with the object model via interfaces. I have actual factory objects (I'm calling them providers) to supply instances that implement these interfaces, but that left the clumsiness of getting the providers. To do so, I've supplied a couple methods on the datasource:
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);
}
}
}
I've modified some details on the fly to simplify (e.g., this code snippet doesn't include the parameters passed to the implementation instance that's created). Is this a good general approach for implementation of a factory method in C#?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您应该退后一步问一下使用工厂方法是否是一个好主意?在我看来,事实并非如此。
工厂方法存在多个问题,您的示例说明了几个问题:
我建议您查看依赖注入 (DI),而不是尝试手动控制依赖项。每当您的代码需要 IFooProvider 时,请通过构造函数注入为其提供。
You should rather take a step back and ask whether using a factory method at all is a good idea? In my opinion, it is not.
There are more than one issue with factory methods, and your example illustrates several:
Instead of trying to manually control dependencies, I would recommend that you take a look at Dependency Injection (DI). Whenever your code needs an IFooProvider, supply it with Constructor Injection.
不要重新发明自己的依赖注入实现,使用现有的库,例如 Spring.NET 或 Microsoft Unity 应用程序块。
注入依赖项是一个常见的编程问题,您不必自己解决。有一些不错的轻量级库(我上面提到了几个)可以很好地完成这项工作。它们支持定义依赖关系的声明式和命令式模型,并且非常擅长它们所做的事情。
Don't reinvent your own implementation of dependency injection, use an existing library like Spring.NET or the Microsoft Unity application block.
Injecting dependencies is a common programming problem that you shouldn't have to solve yourself. There are some nice lightweight libraries out there (I mentioned a couple above) that do the job well. They support both declarative and imperative models of defining dependencies and are quite good at what they do.
从技术上讲,这很好,但是大多数时候,当我看到工厂时,它通常返回相同类型的接口,例如类似
IProvider
而不是IFooProvider
或IBarProvider
代码> 这对我来说没有意义。如果您打算拥有 FooProvider 和 BarProvider 那么为什么要为它们提供不同的接口。我将使用一个接口IProvider
并让FooProvider
和BarProvider
实现该接口。Technically this is fine, however most times when I see a factory it usually returns the same type interface, for instance something like
IProvider
rather thanIFooProvider
orIBarProvider
which to me doesn't make sense. If you are going to have FooProvider and BarProvider then why have different interfaces for them. I would use one interfaceIProvider
and haveFooProvider
andBarProvider
implement that.无论使用工厂方法正确还是错误(因为这不是您所问的!),您的实现对我来说看起来都很好。
比硬编码类型映射更适合您的方法是将该信息放入配置文件中并将其加载到您的应用程序中。
Regardless of the rightness or wrongness of using the factory method (as that is not what you asked about!), your implementation looks fine to me.
Something that may work for you better than hardcoding the type mapping is putting that info in a configuration file and loading it in your app.
出于价值,我一直使用这种模式,并将一些此类逻辑抽象到可重用的程序集中。它使用反射、泛型和属性在运行时定位和绑定具体类型。 http://www.codeproject.com/KB/architecture/RuntimeTypeLoader.aspx
这有助于解决 Mark 的担忧,因为实现类型不是硬编码的,而且实现类型是由安装确定的,而不是在项目程序集引用中确定的。
For what it is worth I use this pattern all the time and have abstracted some of this sort of logic into a reusable assembly. It uses reflection, generics and attributes to locate and bind the concrete types at runtime. http://www.codeproject.com/KB/architecture/RuntimeTypeLoader.aspx
This helps to address Mark's concern because implementation types are not hardcoded, and further the implementation types are determined by the installation, not in project assembly references.