我正在尝试以正确的方式实现工厂模式,但是我不确定这是否正确。我从这样的基类派生了三个模型类:
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");
这是最好的方法吗?我应该将三个“创建”函数分成各自的单独类吗?使用泛型会更有意义吗?
答案 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;
}