如何初始化工厂?
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-injection 和 inversion-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...
}
我有一个制造汽车的工厂...它是一个基本工厂,它接受汽车名称,查找所有实施 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-injection 和 inversion-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...
}