2010-03-23 103 views
3

几天前我做了一个similar question,但现在我有了新的需求,并且新的挑战=)。像往常一样,我使用动物枚举的教学目的,一旦我不想解释领域特定的东西Java枚举:从另一个枚举中收集信息

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

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请求过多?

回答

8

你尝试EnumSetEnumMap

您可以创建一个方法

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

+1不知道EnumSet。很酷的东西! – sfussenegger 2010-03-23 23:15:16

+0

即将发布类似的答案..我觉得它更清洁,而不是返回布尔值。延伸也更容易。 +1 – 2010-03-23 23:16:51

+0

这似乎是一个很好的。去尝试一下(并且接受它,以防万一它让我开心= P) – 2010-03-23 23:20:37

0

我不知道你为什么要把它在另一个枚举,当你可以把它放在函数:

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

这看起来不错,只是一个小例子。但是如果你长大一点(比如5个类别,每个类别有10个动物),它对于一个枚举就开始非常大。我希望它尽可能愚蠢 – 2010-03-23 23:17:05

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

Awesome Answer .. +1 – 2013-12-12 11:14:47

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

记住枚举只当你需要di时很有用代码中的细分对象 - 除了可以作为代码输入外,它们是无用的。

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

例如,你如何使用这些除了像声明:

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

这应该即时提醒任何OO程序员 - 交换机是一个坏的代码味道,因为他们几乎总是表明坏的面向对象的设计)。

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

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

通常,使用OO进行编程而不是使用开关和枚举会折叠大量的代码。

每次你写一个方法时,都要记住“不要问对象获取数据,然后对对象进行操作,而是要求对象为你做一个操作”。

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

你不能扩展EnumSet:构造函数是包保护的。 – 2012-06-04 21:24:44