1

假设我正在创建一个体育游戏,在这个游戏中玩家可以扮演各种位置,进攻,防守等。所以我首先创建一个基类:

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

我应该看什么解决方案?这是哪种设计模式?

4

4 回答 4

5

如果您必须在小范围内执行此操作,则开关并不是很糟糕,特别是如果它位于一个地方。

如果您必须在中等规模上执行此操作,您可能需要考虑稍微改进一下内部结构——Steve Ellinger 的建议是合理的。就我个人而言,我更喜欢使用IDictionary<MyEnum, Action<T>>Action 返回相关类的新实例的地方。

如果您必须在一个宏大或可配置的规模上执行此操作,您可能应该检查 IoC 控制器,例如结构映射或 ninject 或任何酷孩子正在玩的这些天。

于 2010-10-10T01:52:12.993 回答
3

听起来像工厂模式

然而,拥有一个 switch case 可能不是一件坏事,它打开一个枚举/字符串以返回正确类型的对象......只要它被隔离在一个地方

于 2010-10-09T18:04:34.200 回答
2

事实上,你想要的是一个抽象工厂。实现工厂的难易程度取决于您使用的语言。例如,php 允许使用变量类名,因此您只需发送类名并返回新的 $classname。但是,其他语言不允许这样做。事实上,如果你的语言不这样做,你已经创建了一个工厂类!

除非您想使用反射来模拟 php 所做的事情,否则您实际上没有什么比这更优雅的了。

于 2010-10-09T18:21:46.620 回答
1

处理开关的一种方法是让工厂声明一个类型数组,然后使用枚举作为数组的索引,如下所示:

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;
    }
}
于 2010-10-10T01:31:02.853 回答