简体   繁体   English

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

[英]Java enums: Gathering info from another enums

I made a similar question a few days ago, but now I have new requirements, and new challenges =). 我几天前提出了类似的问题 ,但现在我有了新的要求,新的挑战=)。 As usual, I'm using the animal enums for didactic purposes, once I don't want to explain domain-specific stuff 像往常一样,一旦我不想解释特定领域的东西,我就会将动物枚举用于教学目的

I have a basic enum of animals, which is used by the whole zoo (I can add stuff to it, but must keep compatibility): 我有一个动物的基本枚举,整个动物园都使用它(我可以添加东西,但必须保持兼容性):

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

I need to categorize them in a few, non-related categories, like gray animals (whale (my whale is gray) and elephant), small animals (bird, shrimp and dog), sea animals (whale and shrimp). 我需要将它们归类为几个不相关的类别,如灰色动物(鲸鱼(我的鲸鱼是灰色的)和大象),小动物(鸟,虾和狗),海洋动物(鲸鱼和虾)。

I could, as suggested in my previous questions, add a lot of booleans, like isGray, isSmall and isFromSea, but I'd like an approach where I could keep this somewhere else (so my enum doesn't need to know much). 我可以像我之前的问题中所建议的那样添加很多布尔值,比如isGray,isSmall和isFromSea,但是我想要一种方法,我可以把它保存在其他地方(所以我的枚举不需要知道多少)。 Something like: 就像是:

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

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

Somewhere else 别的地方

public enum GrayAnimal {
  WHALE,
  ELEPHANT;
}

How is this possible? 这怎么可能? Am I requesting too much from Java? 我是否要求Java过多?

Did you try EnumSet or EnumMap ? 你尝试过EnumSetEnumMap吗?

You can create a method 您可以创建一个方法

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

I think it would be best to store such properties in the enum instances themselves, ie 我认为最好将这些属性存储在枚举实例中,即

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

You could even encode several boolean properties into one byte (or use BitSet instead); 你甚至可以将几个布尔属性编码为一个字节(或者改为使用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;
  }
}

Nevertheless, what about simply doing this: 然而,简单地这样做:

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

or something like this 或类似的东西

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

Remember that enums are only useful when you need to differentiate objects in your code--they are useless except that they can be typed in as code. 请记住,只有当您需要区分代码中的对象时,枚举才有用 - 除了可以作为代码输入外,它们是无用的。

This is relevant because you are introducing elements into your software that will turn out to be bad code smells in the long run. 这是相关的,因为您在软件中引入元素,从长远来看,这些元素会变成糟糕的代码味道。

For instance, how do you use these except in statements like: 例如,除了语句之外,你如何使用它们:

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

This should instantly alert any OO programmer--switches are a bad code smell since they almost always indicate bad OO design). 这应该立即警告任何OO程序员 - 开关是一个糟糕的代码气味,因为他们几乎总是指示不良的OO设计)。

The alternative is to create a finite set of objects, initialized by data, preferably not code. 另一种方法是创建一组有限的对象,由数据初始化,最好不是代码。

You might have an instance of critter with the attributes of a whale--perhaps whale.move() would use an instance of WaterMovement whereas the elephant contains and uses an instance of LandMovement. 你可能有一个具有鲸鱼属性的生物实例 - 也许whale.move()将使用WaterMovement的实例,而大象包含并使用LandMovement的实例。

In general, programming in OO instead of using switches and enums will collapse an amazing amount of code. 通常,在OO中编程而不是使用开关和枚举将会破坏大量的代码。

Every time you write a method, remember the mantra "Don't ask an object for data and then operate upon the object, instead ask the object to do an operation for you". 每次编写方法时,请记住“不要向对象询问数据然后对对象进行操作,而是要求对象为您执行操作”的口头禅。

I don't know why you want to put it in another enum, when you could put it in that function: 我不知道你为什么要把它放在另一个枚举中,当你可以把它放在那个函数中时:

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

maybe something like this: 也许是这样的:

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

I think that it is best not to pollute your enum with this sort of categorization. 我认为最好不要通过这种分类来污染你的枚举。 It is best to decouple the categories from the enum so you can add more later without affecting your enum. 最好将类别与枚举分离,以便以后可以添加更多类别,而不会影响枚举。 This follows the seperation of concerns and single responsibility principle for class design. 这是对课堂设计的关注点和单一责任原则的分离。

To do this, just use an EnumSet to hold the instances, viz: 要做到这一点,只需使用EnumSet来保存实例,即:

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

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

If you want to add functionality above simple membership, or you want a bit more syntactic sugar extend EnumSet 如果你想在简单成员资格之上添加功能,或者你想要更多的语法糖扩展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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM