假设我正在创建一个体育游戏,在这个游戏中,玩家可以玩各种姿势,攻击,防御等。 所以我首先创建一个基类:
public abstract class Position
{
public abstract string Name
{
get;
}
}
和子类......
public class Defender : Position
{
public override string Name
{
get { return "Defender"; }
}
}
等等。这一切都很好。
但是现在我需要一个函数来创建这些对象。我需要一个按位置功能创建。因此,一种可能的解决方案是创建所有位置的枚举,并将此值传递给一个函数,该函数打开枚举并返回适当的对象。但这会触发我的代码闻到警报。这个灵魂将函数中的类,枚举和开关联系在一起:
public static Position GetByType(Types position)
{
switch(position)
{
case Types.Defender:
return new Defender();
... and further terrible code
我应该考虑什么解决方案?这是哪种设计模式?
答案 0 :(得分:4)
如果你必须小规模地做这件事,那么转换并不是很糟糕,特别是如果它住在一个地方。
如果你必须在中等规模上这样做,你可能要考虑改善内部因素 - 史蒂夫·埃林格的建议是合理的。我个人更喜欢使用IDictionary<MyEnum, Action<T>>
,其中Action返回相关类的新实例。
如果您必须在宏观或可配置的范围内执行此操作,您可能应该查看一个IoC控制器,例如structuremap或ninject,或者这些天酷孩子正在玩的任何东西。
答案 1 :(得分:3)
听起来像Factory pattern。
然而,有一个switch case可能并不坏,它会打开一个enum / string来返回正确类型的对象....只要它在一个地方被隔离
答案 2 :(得分:1)
的确,你想要的是一个抽象的工厂。实施工厂的难易程度取决于您使用的语言。例如,php允许变量类名,因此您只需发送类名并获取新的$ classname。但是,其他语言不允许这样做。事实上,如果您的语言没有这样做,那么您已经创建了一个工厂类!
除非你想用反射来模拟php的功能,否则你无法做到更优雅。
答案 3 :(得分:1)
处理切换的一种方法是让工厂声明一个Types数组,然后使用枚举作为数组的索引,如下所示:
public abstract class Position {
public abstract string Name {
get;
}
}
public class Defender : Position {
public override string Name {
get { return "Defender"; }
}
}
public class Attacker : Position {
public override string Name {
get { return "Attacker"; }
}
}
public static class PositionFactory {
public enum Types {
Defender, Attacker
}
private static Type[] sTypes = new Type[] { typeof(Defender), typeof(Attacker)};
public static Position GetByType(Types positionType) {
return Activator.CreateInstance(sTypes[(Int32)positionType]) as Position;
}
}