4

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

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# 中实现工厂方法的一种很好的通用方法吗?

4

5 回答 5

4

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

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

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

与其尝试手动控制依赖关系,我建议您查看依赖注入 (DI)。每当您的代码需要 IFooProvider 时,请使用构造函数注入为其提供。

于 2009-10-26T15:19:04.783 回答
3

不要重新发明你自己的依赖注入实现,使用现有的库,如Spring.NETMicrosoft Unity应用程序块。

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

于 2009-10-26T15:41:54.943 回答
1

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

于 2009-10-26T15:19:59.340 回答
0

不管使用工厂方法是对还是错(因为这不是你问的!),你的实现对我来说看起来不错。

比硬编码类型映射更适合您的方法是将这些信息放在配置文件中并将其加载到您的应用程序中。

于 2009-10-26T15:22:49.817 回答
0

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

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

于 2009-10-26T15:53:18.867 回答