2

对于竞技场游戏,我有一个可能的游戏类型的枚举。这些游戏类型中的每一个都有一个与之关联的变体列表以及每个枚举的 2 个类,用于侦听事件和处理配置值。目前,我从枚举中构建这些侦听器和配置加载器。在这样做时,我必须使用 switch 语句。以下方法从枚举值获取侦听器。

public GameListener getListener(CustomGame cg) {
    switch(this) {
    case Slayer:
        return new SlayerListener(cg);
    case Capture_The_Flag:
        return new CaptureTheFlagListener(cg);
    case Oddball:
        return new OddballListener(cg);
    case HeadHunter:
        return new HeadHunterListener(cg);
    case King_Of_The_Hill:
        return new KOTHListener(cg);
    default:
        return null;
    }
}

配置存在类似的代码。我知道使用抽象方法可以删除 switch 语句,但我想知道是否有更简单的方法。我试图让我的枚举采用 2 个类型参数,但我无法让它工作,我也无法用它们进行构造。一种选择是Class<T>通过反射传入并构造对象。

这个类中还有另一种方法,每个枚举都有非常不同的布局,我认为最好的选择是抽象方法,但我觉得这里有一个更简单的解决方案。

4

3 回答 3

4

这有点冗长,但您可以直接在枚举类型上提供工厂方法:

public enum GameType {
  SLAYER {
    @Override
    public GameListener getListener(CustomGame cg)
      return new SlayerListener(cg);
    }
  },
  // ... similarly for other GameListener types

  public abstract GameListener getListener(CustomGame cg);
}

这个解决方案的好处是,如果GameType不定义getListener()方法的实现,现在就不可能创建一个新的。

于 2013-10-28T20:41:46.907 回答
1

这是一种工厂方法,我认为在这种情况下使用开关是完全有效的。另一种方法是创建侦听器的继承层次结构,并声明对侦听器的(可能是抽象的)超类的引用,而在运行时您将为引用实例化正确的侦听器。也许太麻烦了,但更面向对象。这是需要大量类的良好 OO 设计与充满 switch 语句的代码之间的权衡,请自行选择。

于 2013-10-28T20:33:51.240 回答
0

如果性能无关紧要,您可以使用这样的通用 GameListener Getter:

public Listener getListener( CustomGame cg ) {
    // implement some smart way to find your listener implementation here...
    Class<? extends Listener> clzz = Class.forName( this.getClass().getPackage() + "." + name() );
    Listener ret = clzz.newInstance();
    ret.setCustomGame(cg);
    return ret;
}

这将不需要维护,也不需要枚举中的特殊参数。但当然,它将枚举名称直接链接到创建的类名称,这可能不是所需的约束。

于 2013-10-28T20:59:14.520 回答