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

发布于 2024-08-08 18:53:10 字数 960 浏览 9 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

真心难拥有 2024-08-15 18:53:10

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

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

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

我建议您查看依赖注入 (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:

  • You need to have a hard reference to the implementation (FooProvider in addition to IFooProvider), which is exactly the situation you are trying to avoid in the first place. Even if the rest of your code only consumes IFooProvider, your library is still tightly coupled to FooProvider. Some other developer may come by and start using FooProvider directly if he/she isn't aware of your factory method.
  • You only support implementations that have default constructors, since you are using Activator.CreateInstance. This prevents you from using nested dependencies.

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.

羁拥 2024-08-15 18:53:10

不要重新发明自己的依赖注入实现,使用现有的库,例如 Spring.NETMicrosoft 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.

树深时见影 2024-08-15 18:53:10

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

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 than IFooProvider or IBarProvider 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 interface IProvider and have FooProvider and BarProvider implement that.

豆芽 2024-08-15 18:53:10

无论使用工厂方法正确还是错误(因为这不是您所问的!),您的实现对我来说看起来都很好。

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

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.

江挽川 2024-08-15 18:53:10

出于价值,我一直使用这种模式,并将一些此类逻辑抽象到可重用的程序集中。它使用反射、泛型和属性在运行时定位和绑定具体类型。 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文