工厂模式:枚举或类型?

时间:2009-05-08 16:32:31

标签: c# design-patterns

在实现工厂或简单工厂时,使用Type而不是Enum来指定要实例化的类会不会怎样?

例如

public class SimpleFactory
{
 public static ITest Create(Type type)
 {
  if (type == typeof(ConcreteTest1))
   return new ConcreteTest1();
  if (type == typeof(ConcreteTest2))
   return new ConcreteTest2();

  throw new Exception("Invalid type");
 }
}

6 个答案:

答案 0 :(得分:15)

使用枚举更具限制性,这意味着用户不太可能尝试使用不受支持的类型的工厂。

我发现在定义API时尽一切可能阻止使用模式会导致异常被抛出。在这种情况下允许“类型”会打开数百万种调用函数的方法,这将导致:

throw new Exception("Invalid type");

使用枚举可以消除这种情况。枚举的唯一方法就是如果用户做了明显错误的事情。

答案 1 :(得分:4)

只有在对象上执行配置或初始化以使它们处于有效状态时,工厂才有用。如果它只是新的并返回对象,我不会打扰工厂。

我会为每个类层次结构创建一个工厂。例如:

public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}

public class VehicleFactory
{
    public Vehicle CreateVehicle<T>() where T : Vehicle
    {
        // Get type of T and delegate creation to private methods
    }
}

答案 2 :(得分:2)

如果你想要一个防呆工厂,你必须为每种混凝土类型创建一个混凝土工厂。本课程不遵循开放式原则:每次有新的具体类型时,你都要重新编辑这个课程。

恕我直言,更好的方法是使用继承,每种具体类型都有一个具体的工厂类。

答案 3 :(得分:2)

我更喜欢使用泛型约束,因为有一个enum只是为了指定你想要的对象类型对我来说似乎是多余的,并且使用你所描述的类型违反了开放/封闭原则。我所做的与你所做的不同的是约束你的类型,以便只传入允许的类型。

我将使用泛型在c#中给出一个例子。

public class SimpleFactory
{
 public static ITest Create<T>()
    where T: ITest, new()
 {
    return new T();
 }
}

然后你将使用ConcreteTest1和ConcreteTest2实现IConcreteTest,你可以像这样使用你的工厂:

ConcreteTest1 test1 = SimpleFactory.Create<ConcreteTest1>();

答案 4 :(得分:1)

如果您想按类型创建,则可以使用Activator.CreateInstance(Type t)。将其包装在模板方法中以将其限制为您的界面,例如Create<T> where T:ITest

答案 5 :(得分:1)

我认为我最关心的是工厂的目的是允许客户端代码创建对象的派生实例,而不知道正在创建的类型的细节(更具体地说,如何的细节)创建实例,但如果正确完成,调用者不应该知道超出基类提供的任何细节。

使用从派生类型中提取的类型信息仍然需要调用者对他想要实例化哪种类型有一些了解,这使得更新和维护变得困难。通过替换Enum类型(或字符串,int等),您可以更新工厂而无需更新调用代码以了解新的派生类型。

我想有人可能会认为类型名称可以作为来自配置文件,数据库等的字符串读入,并且使用Reflections(在.NET中)或RTTI(在C ++中)确定类型信息,但是我认为这是一个更好的情况,只需使用类型字符串作为您的标识符,因为它将有效地用于相同的目的。