2010-03-23 5 views
3

J'ai fait un similar question il y a quelques jours, mais maintenant j'ai de nouvelles exigences, et de nouveaux défis =). Comme d'habitude, j'utilise les énumérations d'animaux à des fins didactiques, une fois que je ne veux pas expliquer les choses spécifiques au domaineJava enums: Collecte d'informations à partir d'un autre enums

J'ai une base d'animaux, qui est utilisée par le zoo entier (je peux ajouter des choses à, mais doit garder la compatibilité):

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

J'ai besoin de les classer dans quelques, catégories non liées, comme des animaux gris (baleine (ma baleine est gris) et l'éléphant), les petits animaux (oiseaux, crevette et chien), les animaux marins (baleine et crevette). Je pourrais, comme suggéré dans mes questions précédentes, ajouter beaucoup de booléens, comme isGray, isSmall et isFromSea, mais je voudrais une approche où je pourrais garder ceci ailleurs (ainsi mon énumération n'a pas besoin de savoir beaucoup). Quelque chose comme:

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

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

Ailleurs

public enum GrayAnimal { 
    WHALE, 
    ELEPHANT; 
} 

Comment est-ce possible? Est-ce que je demande trop de Java?

Répondre

8

Avez-vous essayé EnumSet ou EnumMap?

Vous pouvez créer une méthode

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

+1 ne savait pas à propos d'EnumSet. truc cool! – sfussenegger

+0

Étais sur le point de poster une réponse similaire .. Je trouve qu'il est plus propre d'avoir des ensembles au lieu de retourner les booléens. C'est aussi beaucoup plus facile à étendre. +1 –

+0

Cela semble être un bon. Je vais l'essayer (et l'accepter au cas où cela me ferait plaisir = P) –

0

Je ne sais pas pourquoi vous voulez le mettre dans une autre ENUM, alors que vous pourriez mettre dans cette fonction:

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

Cela semble bon pour un petit exemple. Mais si vous grandissez un peu (disons 5 catégories, avec 10 animaux chacun), il commence à être très gros pour une énumération. Je voulais que ce soit aussi stupide que possible –

2

Je pense qu'il serait préférable de conserver ces propriétés dans les cas enum eux-mêmes, à savoir

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

Vous pouvez même encoder plusieurs propriétés booléennes dans un octet (ou utilisez BitSet à la place);

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

Néanmoins, qu'en faisant simplement ceci:

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

ou quelque chose comme ça

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

Impressionnant Réponse .. +1 –

0

peut-être quelque chose comme ceci:

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

Rappelez-vous que les énumérations ne sont utile lorsque vous avez besoin de di fférentiate objets dans votre code - ils sont inutiles, sauf qu'ils peuvent être tapés en code. Ceci est important parce que vous introduisez dans votre logiciel des éléments qui s'avéreront être de mauvaises odeurs de code à long terme.

Par exemple, comment utilisez-vous ces sauf dans des déclarations comme:

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

Cela devrait immédiatement alerter tout programmeur OO - commutateurs sont une mauvaise odeur de code, car ils indiquent presque toujours une mauvaise conception OO).

L'alternative est de créer un ensemble fini d'objets, initialisés par des données, de préférence pas de code.

Vous pourriez avoir une instance de critter avec les attributs d'une baleine - peut-être whale.move() utiliserait une instance de WaterMovement alors que l'éléphant contient et utilise une instance de LandMovement.

En général, la programmation dans OO au lieu d'utiliser des commutateurs et des enums réduira une quantité incroyable de code.

Chaque fois que vous écrivez une méthode, souvenez-vous du mantra "Ne demandez pas à un objet des données, puis opérez sur l'objet, demandez plutôt à l'objet de faire une opération pour vous".

0

Je pense qu'il est préférable de ne pas polluer votre énumération avec ce genre de catégorisation. Il est préférable de découpler les catégories de l'énumération pour pouvoir en ajouter plus tard sans affecter votre énumération. Cela suit la séparation des préoccupations et le principe de responsabilité unique pour la conception de classe.

Pour ce faire, il suffit d'utiliser un EnumSet pour tenir les instances, à savoir:

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

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

Si vous voulez ajouter des fonctionnalités ci-dessus simples membres, ou si vous voulez un peu plus de sucre syntaxique étendre 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

Vous ne pouvez pas étendre EnumSet: Le constructeur est protégé par un paquet. –