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

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

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

有帮助吗?

解决方案

如果您必须小规模执行此操作,则开关并不是很糟糕,尤其是如果它生活在一个地方。

如果您必须在中等规模上这样做,则可能需要考虑将内部设备改进一些 - 史蒂夫·埃林格(Steve Ellinger)的建议是合理的。我个人更喜欢使用 IDictionary<MyEnum, Action<T>> 操作返回所讨论的课程的新实例的地方。

如果您必须以宏伟或可配置的比例进行此操作,则可能应该检查IOC控制器,例如结构图或NInject,或这些天很酷的孩子们玩的任何东西。

其他提示

听起来像是 工厂模式.

但是,拥有一个开关案例可能不是一件坏事 在一个地方孤立.

确实,您想要的是抽象工厂。实施工厂的易度性取决于您使用的语言。例如,PHP允许使用可变类名称,因此您可以在类名中发送并获得新的$ className。但是,其他语言不允许这样做。实际上,如果您的语言不这样做,那么您已经创建了工厂课程!

除非您想使用反射来模拟PHP的作用,否则您实际上没有什么更优雅的事情。

处理交换机的一种方法是让工厂声明类型数组,然后将枚举用作索引中的索引中的数组:

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;
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top