这是一个很好的工厂方法实现吗?

时间:2009-10-26 15:06:29

标签: c# factory-method

我正在研究一个需要严格解耦的接口的模块。具体来说,在实例化根对象(数据源)之后,用户只应该通过接口与对象模型进行交互。我有实际的工厂对象(我称之为提供者)来提供实现这些接口的实例,但这使得获取提供者变得笨拙。为此,我在数据源上提供了几种方法:

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#中实现工厂方法的一般方法吗?

5 个答案:

答案 0 :(得分:4)

你应该退后一步,询问使用工厂方法是否是一个好主意?在我看来,事实并非如此。

工厂方法存在多个问题,您的示例说明了几个:

  • 您需要对实现(除了IFooProvider之外的FooProvider)有一个硬引用,这正是您首先要避免的情况。即使代码的其余部分仅使用IFooProvider,您的库仍然与FooProvider紧密耦合。如果他/她不了解您的工厂方法,其他一些开发人员可能会直接开始使用FooProvider。
  • 您只支持具有默认构造函数的实现,因为您使用的是Activator.CreateInstance。这可以防止您使用嵌套依赖项。

我建议您先看一下依赖注入(DI),而不是尝试手动控制依赖关系。每当您的代码需要一个IFooProvider时,请使用Constructor Injection提供它。

答案 1 :(得分:3)

不要重新发明您自己的dependency injection实现,使用现有的库,如Spring.NETMicrosoft Unity应用程序块。

注入依赖项是一个常见的编程问题,您不应该自己解决。有一些不错的轻量级库(我上面提到过几个)可以很好地完成工作。它们支持定义依赖关系的声明性和命令式模型,并且非常擅长于它们的工作。

答案 2 :(得分:1)

从技术上讲,这很好,但是大多数情况下,当我看到工厂时,它通常会返回相同类型的界面,例如IProvider而不是IFooProviderIBarProvider,这对我来说没有没有意义。如果您要使用FooProvider和BarProvider,那么为什么要为它们提供不同的接口。我会使用一个接口IProvider并让FooProviderBarProvider实现该接口。

答案 3 :(得分:0)

无论使用工厂方法的正确与否(因为这不是你所问的!),你的实现对我来说很好。

可能比对代码映射进行硬编码更有效的方法是将该信息放入配置文件并将其加载到您的应用程序中。

答案 4 :(得分:0)

为了它的价值,我一直使用这种模式,并将这种逻辑抽象为可重用的程序集。它使用反射,泛型和属性在运行时定位和绑定具体类型。 http://www.codeproject.com/KB/architecture/RuntimeTypeLoader.aspx

这有助于解决Mark的问题,因为实现类型不是硬编码的,而且实现类型由安装决定,而不是在项目程序集引用中确定。