如何初始化工厂?

How to initialize a factory?

我有一个制造汽车的工厂...它是一个基本工厂,它接受汽车名称,查找所有实施 ICar 的 类,根据汽车选择正确的类型使用反射命名并初始化汽车。

public class CarFactory
{
    Dictionary<string, Type> cars;

    public ICar CreateInstance(string carName)
    {
        // choose type of class from all classes that implement ICar 
        Type t = GetTypeToCreate(carName); 
        return Activator.CreateInstance(t) as ICar;
    }

    // some more code...
}

现在,我有一个使用 CarFactory 的服务。在我的服务中初始化 CarFactory 的正确方法是什么?

一个解决方案是注入工厂,但是工厂模式本身就是 IoC 的一种形式,注入工厂感觉很奇怪。根据Nikola Malovic:

using factories together with IoC doesn’t make a lot of sense because IoC container is in a sense “universal abstract factory”.

In other words, in my experience any time I thought about adding a factory I ended with much simpler IoC based solution so that’s why I would dare to say that “IoC kill the Factory star"

上面的内容对我来说很有意义,尽管我还没有想到用 DI 替换我的工厂的解决方案。

所以我的问题是(对于那些使用工厂模式的人)我应该如何初始化它?


为了避免问题太长,我在这个问题中使用了一个简化的 CarFactory 示例。我已经发布了完整的例子 here.

最好将依赖项(构造函数、属性、方法)注入到您的类型中。并且最好避免使用 new-operator 创建依赖项。

为了让它变得更好,您应该为您定义一个接口 CarFactory (ICarFactory) 并将您的服务更改为依赖于该类型。

在测试中,您可以模拟 ICarFactory 并为您的测试用例提供特殊实现。

我认为比较依赖注入容器和工厂是错误的。
是的,两者的责任都是创建某种类型的实例。

但是 DI 容器负责根据 DI 配置实例化实例及其所有依赖项。通常 DI 容器在应用程序的入口点实例化对象(main 方法或 Web 应用程序中的 request)。

工厂将根据应用程序的某些业务逻辑或某些只能在运​​行时访问的值创建类型的实例。

Factory 与其他 class 一样正常 class 并且可以将其作为依赖项注入。

在您的特定情况下,您仅在运行时知道汽车的名称,因此您将需要一些 class 其职责是 "convert" 汽车实例的名称。

像往常一样,对于这类问题,答案是 It Depends™。这取决于您要解决的问题。虽然这个问题被标记为 dependency-injectioninversion-of-control(在某种程度上 the same idea)none 这些本身就是目标,但只是实现适当目标的手段。

通常,目标是行为 的解耦。这就引出了第一个问题,那么:

为什么 CreateInstance return ICar 个实例?

我这里假设ICar是一个接口。 ICar 是多态的吗?您对该接口有不止一种实现吗?

一个名为 car 的对象对我来说就像一个实体,而那些 should usually not be injected,因为它们通常代表数据,而不是行为。

不过,为了便于讨论,我们假设 ICar 是真正的多态。

如此处所示,CarFactory 看起来是确定性的。不过,这很难说,因为没有显示整个实现。但是,如果它是 referentially transparent,那为什么还要初始化它呢?

它不能只是一个静态函数吗?

public static class CarFactory
{
    public static ICar CreateInstance(string carName)
    {
        // choose type of class from all classes that implement ICar 
        Type t = GetTypeToCreate(carName); 

        return Activator.CreateInstance(t) as ICar;
    }

    // some more code...
}