工厂的正确实施

Correct implementation of factory

我正在尝试以正确的方式实现工厂模式,但我不确定这是否正确。我有三个模型 classes 从基础 class 派生出来,如下所示:

class BaseStyle
{
    public string Name
    {
        get;
        set;
    }
}

class PointStyle : BaseStyle
{
    public PointStyle(string name)
    {
         Name = name;
    }
}

class LineStyle : BaseStyle
{
    public LineStyle(string name)
    {
         Name = name;
    }
}

class PolyStyle : BaseStyle
{
    public PolyStyle(string name)
    {
         Name = name;
    }
}

然后我有一个名为 StyleFactory 的 class。此 class 使用 string 来确定要创建的样式类型和 returns 该样式。

public class StyleFactory
{
    public static BaseStyle CreateStyle(string styleType)
    {
        if (styleType == "point")
        {
            return CreatePointStyle();
        }
        if (styleType == "line")
        {
            return CreateLineStyle();
        }
        if (styleType == "poly")
        {
            return CreatePolytStyle();
        }
    }

    private static PointStyle CreatePointStyle()
    {
        //creates a pointstyle
    }

    private static LineStyle CreateLineStyle()
    {
        //creates a linestyle
    }

    private static PolyStyle CreatePolyStyle()
    {
        //creates a polystyle
    }
}

然后在代码中这样调用:

PointStyle pointStyle = StyleFactory.CreateStyle("point");

这是解决问题的最佳方法吗?我是否应该将三个 "Create" 函数拆分为各自独立的 class?使用泛型会更有意义吗?

我认为不需要像 CreatePolyStyle() 这样的额外抽象方法;相反,您可以简单地创建实例,并且 return 与

相同
    public static BaseStyle CreateStyle(string styleType)
    {       
      BaseStyle style = null;    
   switch(styleType)
   {
        case "point":
            style = new PointStyle("abc");
            break; 
        case "line":
            style = new LineStyle("xyz");
            break; 
        case "poly":
           style = new PolyStyle("def");
           break;
        default:
           break;
   }
     return style;
    }

想想调用者将不得不使用方法的方式:

//Existing
BaseStyle someStyle = factory.CreateStyle("point", name);

这里有两个问题。其中之一是没有对字符串 "point" 进行编译时求值;为了缓解这个问题,您可以使用常量字符串或类似的东西。第二个是 returned 对象只是一个 BaseStyle;为了做任何有趣的事情,客户总是不得不施放它。所以实际上代码将如下所示:

//Practical use of existing
PointStyle pointStyle = (PointStyle)factory.CreateStyle(Constants.StylesPoint, name);

我们可以用泛型解决这两个问题。如果我们以正确的方式定义方法,return 类型会在编译时自动为我们选择。这也意味着类型的选择是在编译时检查的,所以我们不必担心字符串是错误的。调用的示例:

//Using generics
PointStyle pointStyle = factory.CreateStyle<PointStyle>(name);

为了允许调用者以这种方式使用该方法,我们定义了一个类型参数:

public T CreateStyle<T>(string name) where T : BaseStyle
{       
    var type = typeof(T);
    if (type == typeof(PointStyle)) 
    {
        return new PointStyle(name) as T;
    }
    if (type == typeof(LineStyle)) 
    {
        return new LineStyle(name) as T;
    }
    if (type == typeof(PolyStyle) 
    {
        return new PolyStyle(name) as T;
    }
    throw new Exception("The type {0} is not supported.", typeof(T).FullName);
}

或者如果你想聪明一点:

public T CreateStyle<T>(string name) where T : BaseStyle
{       
    try
    {
        return Activator.CreateInstance(typeof(T), new [] { name } );
    }
    catch(MissingMethodException exception)
    {
        throw new InvalidOperationException("The specified style does not have an appropriate constructor to be created with this factory.", exception);      
    }    
}

最后一种方法不需要维护,以后可以添加其他样式;只要它们继承自 BaseStyle,并且包含一个接受名称作为单个字符串参数的构造函数,工厂就能够自动生成它们。

补充说明:

虽然静态工厂方法在几年前风靡一时,但现在它们通常被实现为 实例 方法,因此您可以在 IoC 下注入工厂.如果将方法设为静态,任何调用它的代码都将具有静态依赖性,这很难存根和单元测试。