Java枚举:从其他枚举中收集信息

时间:2010-03-23 23:00:56

标签: java enums

我几天前做了similar question,但现在我有了新的要求,新的挑战=)。像往常一样,一旦我不想解释特定领域的东西,我就会将动物枚举用于教学目的

我有一个动物的基本枚举,整个动物园都使用它(我可以添加东西,但必须保持兼容性):

public enum Animal {
  DOG,
  ELEPHANT,
  WHALE,
  SHRIMP,
  BIRD,
  GIRAFFE;
}

我需要将它们分类为几个非相关的类别,如灰色动物(鲸鱼(我的鲸鱼是灰色的)和大象),小动物(鸟,虾和狗),海洋动物(鲸鱼和虾)。

我可以像我之前的问题中所建议的那样添加很多布尔值,比如isGray,isSmall和isFromSea,但是我想要一种可以将其保存在其他地方的方法(所以我的枚举不需要知道许多)。类似的东西:

public enum Animal {
  DOG,
  ELEPHANT,
  WHALE,
  SHRIMP,
  BIRD,
  GIRAFFE;

  public boolean isGray() {
    // What comes here?
  }
}

其他地方

public enum GrayAnimal {
  WHALE,
  ELEPHANT;
}

这怎么可能?我是否要求Java过多?

6 个答案:

答案 0 :(得分:8)

您是否尝试过EnumSetEnumMap

您可以创建方法

Set<Animal> grayAnimals(){
   return EnumSet.of(Animal.WHALE, Animal.ELEPHANT);
}

答案 1 :(得分:2)

我认为最好将这些属性存储在枚举实例中,即

public enum Animal {
  DOG(NOT_GRAY),
  ELEPHANT(GRAY),
  WHALE(GRAY),
  SHRIMP(NOT_GRAY),
  BIRD(NOT_GRAY),
  GIRAFFE(NOT_GRAY);

  private static boolean GRAY = true;
  private static boolean NOT_GRAY = !GRAY;

  private Animal(boolean isGray) {
    // snip
  }
}

你甚至可以将几个布尔属性编码为一个字节(或者改为使用BitSet);

public enum Animal {
  DOG(),
  ELEPHANT(GRAY | BIG),
  WHALE(GRAY | BIG),
  SHRIMP(),
  BIRD(),
  GIRAFFE(BIG);

  private static byte GRAY = 0x01;
  private static byte BIG = GRAY << 1;

  private final byte _value;

  private Animal() {
    this(0x00);
  }

  private Animal(byte value) {
    _value = value;
  }

  public boolean isGray() {
    return _value & GRAY != 0x00;
  }

  public boolean isBig() {
    return _value & BIG != 0x00;
  }
}

然而,简单地这样做是什么:

public class GrayAnimal {
  public static final Animal ELEPHANT = Animal.ELEPHANT;
  public static final Animal WHALE = Animal.WHALE;
}

或类似的东西

public enum Animal {
  DOG,
  ELEPHANT,
  WHALE,
  SHRIMP,
  BIRD,
  GIRAFFE;

  // thanks to Mihir, I would have used a regular HashSet instead
  public static final Set<Animal> GRAY = Collections.unmodifiableSet(EnumSet.of(ELEPHANT, WHALE));
}

答案 2 :(得分:1)

请记住,枚举仅在您需要区分代码中的对象时才有用 - 除了可以作为代码输入外,它们没用。

这是相关的,因为您在软件中引入元素,从长远来看,这些元素会变成糟糕的代码味道。

例如,除了语句之外,你如何使用这些:

if(critter.type == WHALE)
    critter.movement=WATER;
else if(critter.type == ELEPHANT)

这应该立即警告任何OO程序员 - 开关是一个糟糕的代码气味,因为他们几乎总是指示不良的OO设计。)

另一种方法是创建一组有限的对象,由数据初始化,最好不是代码。

你可能有一个具有鲸鱼属性的生物实例 - 也许whale.move()将使用WaterMovement的实例,而大象包含并使用LandMovement的实例。

通常,在OO中编程而不是使用开关和枚举将会破坏大量代码。

每次编写方法时,请记住“不要向对象询问数据,然后对对象进行操作,而是要求对象为您执行操作”这句咒语。

答案 3 :(得分:0)

我不知道为什么你想把它放在另一个枚举中,当你把它放在那个函数中时:

public boolean isGray() {
     return this == WHALE || this == ELEPHANT;
}

答案 4 :(得分:0)

可能是这样的:

package p;
import java.util.*;
enum Type {
    small,big,grey;
}
enum Animal {
    bird(EnumSet.of(Type.small)),whale(EnumSet.of(Type.big, Type.grey)),elephant(EnumSet.of(Type.big, Type.grey));
    Animal(final EnumSet<Type> types) { this.types=types; }
    EnumSet<Type> types=EnumSet.noneOf(Type.class);
    boolean is(final Type type) { return types!=null?types.contains(type):false; }
    public static void main(String[] arguments) {
        for(Animal a:values()) {
            System.out.println(a+" "+a.types);
        }
    }
}

答案 5 :(得分:0)

我认为最好不要通过这种分类来污染你的枚举。最好将类别与枚举分离,以便以后可以添加更多类别,而不会影响枚举。这是对课堂设计的关注点和单一责任原则的分离。

为此,只需使用EnumSet来保存实例,即:

public enum Animal {
  DOG,
  ELEPHANT,
  WHALE,
  SHRIMP,
  BIRD,
  GIRAFFE;
}

public static final EnumSet<Animal> GRAY_ANIMALS = EnumSet.of(ELEPHANT, WHALE);

如果你想在简单成员资格之上添加功能,或者你想要更多的语法糖扩展EnumSet

public class GrayAnimals extends EnumSet<Animal> {
    public static final GrayAnimals INSTANCE = new GrayAnimals(ELEPHANT, WHALE);
    private GrayAnimals(Animal...animals) {
        Collections.addAll(this, animals);
    }
    public boolean isGray(Animal animal) { return contains(animal); }
    // ... other methods
}