代码之家  ›  专栏  ›  技术社区  ›  Samuel Carrijo

Java枚举:从另一个枚举收集信息

  •  3
  • Samuel Carrijo  · 技术社区  · 15 年前

    我做了一个 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 回复  |  直到 15 年前
        1
  •  8
  •   Mihir Mathuria    15 年前

    你试过了吗 EnumSet EnumMap ?

    您可以创建一个方法

    Set<Animal> grayAnimals(){
       return EnumSet.of(Animal.WHALE, Animal.ELEPHANT);
    }
    
        2
  •  2
  •   sfussenegger    15 年前

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

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

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

    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));
    }
    
        3
  •  1
  •   Bill K    15 年前

    记住,只有当您需要区分代码中的对象时,枚举才有用——它们除了可以作为代码输入之外,是无用的。

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

    例如,除了在以下语句中之外,如何使用这些语句:

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

    这应该会立即提醒任何OO程序员——开关是一种糟糕的代码味道,因为它们几乎总是指示糟糕的OO设计)。

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

    你可能有一个具有鲸鱼属性的生物实例——也许whale.move()会使用一个watermovement实例,而大象则包含并使用一个lombovement实例。

    一般来说,在OO中编程而不是使用开关和枚举将导致大量代码崩溃。

    每次你写一个方法时,记住“不要向一个对象索要数据,然后对该对象进行操作,而是让该对象为你做一个操作”。

        4
  •  0
  •   wsorenson    15 年前

    我不知道您为什么要将它放入另一个枚举中,当您可以将它放入该函数时:

    public boolean isGray() {
         return this == WHALE || this == ELEPHANT;
    }
    
        5
  •  0
  •   Ray Tayek    15 年前

    可能是这样的:

    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);
            }
        }
    }
    
        6
  •  0
  •   Dean Povey    15 年前

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

    为此,只需使用一个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
    }