【问题标题】:Enums with inherited functionality具有继承功能的枚举
【发布时间】:2018-03-11 18:30:17
【问题描述】:

我有以下用于现实生活设备的枚举常量:

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

我还有一个名为Battle 的课程,它规定了可以在特定战斗中使用哪些装备。例如:

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

这意味着只能使用锤子、盾牌或弓箭。

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

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

相当于说:

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

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

由于Enums 是最终的,我尝试了以下方法:

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&lt;Weapon&gt; values() 会导致编译错误,因为它试图用不同的返回类型覆盖超类中的values()。我能够使用泛型 (&lt;? extends Weapon&gt;) 解决这个问题,但它仍然是一个糟糕的解决方案。

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

【问题讨论】:

  • 这是Java代码吗?如果是,您应该添加java 标签。
  • 我真的不明白你为什么需要继承。看来您只需要各种枚举集(或数组,eek!)。为什么不在 Equipment 枚举中添加一个静态武器()方法,返回所有武器?

标签: java inheritance enums


【解决方案1】:

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

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

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);
  }

}

这种方法仍然不涉及继承或更高级的类型,我认为如果您想要更大的灵活性,最好完全避免使用枚举。

【讨论】:

  • 这绝对不错,但我认为利用继承或接口有更好的解决方案。这感觉就像我在硬编码一个解决方案,因为例如MACESWORDHAMMER,必须重复两次。我希望有办法让我定义MACE时,它可以理解为MeleeWeapon,也就是Weapon,也就是Equipment
  • @Hatefiend 枚举可以有一个状态。您可以向枚举添加类型字段,并从方法中返回给定类型的所有枚举实例。
  • @Antot 好的,我明白了。仍然不是最优雅的方法,但它有效。感谢您的帮助。
猜你喜欢
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多