具有继承功能的枚举

时间:2018-03-11 18:30:17

标签: java inheritance enums

我有以下现实设备的Enum常数:

HELMET,
CHESTPIECE,
BOOTS,
SWORD,
MACE,
HAMMER,
SHIELD,
BOW,
CROSSBOW,
STAFF
...;

我还有另一个名为Battle的班级,该班级规定在特定的战斗中可以使用哪些装备。例如:

new Battle(Equipment.HAMMER, Equipment.SHIELD, EQUIPMENT.BOW);

这意味着只能使用Hammers,Shields或Bows。

现在我对此进行了扩展,并且需要子类别。例如:

new Battle(Equipment.SHIELD, Equipment.Weapons.values())

这相当于说:

new Battle(Equipment.SHIELD, Equipment.SWORD, Equipment.MACE, Equipment.HAMMER, ...)

这也意味着new Battle(Equipment.values())应该产生每个枚举值

由于Enum是最终的,我尝试了以下内容:

public interface Equipment { }

public enum MeleeWeapon implements Equipment
{
    SWORD,
    MACE,
    HAMMER,
    STAFF, ...;
}

public enum RangedWeapon implements Equipment
{
    BOW, CROSSBOW;
}

...

但有了这个,我无法说Equipment.Weapon.values() // get all weapons, ranged and melee。类之间没有任何继承关系的感觉,我也失去了界面中未定义的所有内容。在这里,它并不是一个好的解决方案。

我尝试过定期上课:

public abstract class Equipment
{
    private static Set<Equipment> instances = new HashSet<>();

    public static Set<Equipment> values()
    {
        return instances;
    }

    public Equipment()
    {
        instances.add(this);
    }
}

public abstract class Weapon extends Equipment
{
    private static Set<Weapon> instances = new HashSet<>();

    public static Set<Weapon> values()
    {
        return instances;
    }

    public Weapon()
    {
        super() // explicit call
        instances.add(this);
    }
}

public class MeleeWeapon extends Weapon
{
    private static Set<MeleeWeapon> instances = new HashSet<>();

    public static final MeleeWeapon SWORD = new MeleeWeapon();
    public static final MeleeWeapon MACE = new MeleeWeapon();
    ...

    public static Set<MeleeWeapon> values()
    {
        return instances;
    }

    public MeleeWeapon()
    {
        super() // explicit call
        instances.add(this);
    }
}

不幸的是,有大量重复的代码,内存很重,而且public static Set<Weapon> values()也会导致编译错误,因为它尝试使用不同的返回类型覆盖超类中的values()。我能够用泛型(<? extends Weapon>)解决这个问题,但它仍然是一个糟糕的解决方案。

这里的正确方法是什么?我需要继承我的枚举值,但我找不到如何做的方法。

1 个答案:

答案 0 :(得分:3)

仍然保持枚举用法,可以将枚举的每个元素与它所属的组相关联,然后以专用方法返回过滤的元素组。

我们需要另一个 - 更小 - 枚举枚举要过滤的属性,例如:

public enum EquipmentType {

  WEAPON, ARMOR, TOOL, CLOTHING;

}

枚举的元素与各自的组相关联:

public enum Equipment {

  HELMET(ARMOR),
  CHESTPIECE(ARMOR),
  BOOTS(ARMOR, CLOTHING),
  SWORD(WEAPON),
  MACE(WEAPON),
  HAMMER(WEAPON, TOOL),
  SHIELD(ARMOR),
  BOW(WEAPON),
  CROSSBOW(WEAPON),
  STAFF(WEAPON);

  private final Set<EquipmentType> types;

  Equipment(EquipmentType... eqTypes) {
    this.types = Arrays.stream(eqTypes)
                       .collect(Collectors.toSet());
  }

  // common filtering method
  private static List<Equipment> filterByType(EquipmentType type) {
    return Arrays.stream(values())
        .filter(eq -> eq.types.contains(type))
        .collect(Collectors.toList());
  }

  // dedicated methods for each group of items
  public static List<Equipment> getWeapons() {
    return filterByType(WEAPON);
  }

  public static List<Equipment> getArmor() {
    return filterByType(ARMOR);
  }

}

这种方法仍然没有继承或更多的进化类型,我认为如果你想要更多的灵活性,最好避免使用枚举。