正确实施工厂

时间:2019-03-11 19:22:59

标签: c# design-patterns factory

我正在尝试以正确的方式实现工厂模式,但是我不确定这是否正确。我从这样的基类派生了三个模型类:

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的类。此类使用string确定要创建的样式类型并返回该样式。

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");

这是最好的方法吗?我应该将三个“创建”函数分成各自的单独类吗?使用泛型会更有意义吗?

2 个答案:

答案 0 :(得分:2)

考虑调用者必须使用该方法的方式:

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

这里有两个问题。其中之一是没有对字符串“ point”的编译时求值;为了减轻这个问题,您可以使用常量字符串或类似的字符串。第二个是返回的对象只是一个BaseStyle;为了做任何有趣的事情,客户总是必须抛弃它。因此,实际上代码将如下所示:

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

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

//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,并且它们包含接受名称作为单个字符串参数的构造函数,则工厂将能够自动生成它们。

附加说明:

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

答案 1 :(得分:1)

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

    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;
    }