2012-01-03 15 views
5

estoy tratando de encontrar un equivalente Java para el siguiente conveniencia en C++:enumeración C-como en Java

enum { 
    ANIMAL_CAT = 0, 
    ANIMAL_RAT, 
    ANIMAL_BAT, ... 
    NUM_ANIMALS 
}; 

Animal animals[NUM_ANIMALS]; 

animals[ANIMAL_CAT].mNumLegs = 4; 
animals[ANIMAL_RAT].mNumLegs = 4; ... 

Sé que esto no es la cosa más bonita del mundo, pero puede agregar una nuevo ANIMAL_xxx en cualquier lugar de la enumeración y todas las siguientes entradas se ajustarán automáticamente. ¿Hay una manera limpia de hacer esto en Java?


Gracias por las respuestas, pero puedo haber aludido a una mayor simplicidad de la que pretendía.

Estoy trabajando en un juego, donde hay una física, un motor de IA, etc. Estoy tratando de consolidar toda la información que necesito para cada tipo de entidad (algunos tienen solo una manifestación física, mientras que otros tienen ambos phys y AI, etc ...), de modo que puedo agregar/modificar fácilmente tipos (entonces, animal es un mal ejemplo, porque puedo necesitar rocas, plantas, etc.).

Estoy usando una clase para almacenar la información de tipo, mientras que otras clases dependen de esa clase para buscar los atributos (dimensiones, índice de mapa de bits, hasAi, etc.) Al final, estoy tratando de limpiar algo similar a lo siguiente, mientras que lo que me permite añadir fácilmente nuevos tipos:

class UnitTypeInfo { 
    UnitTypeInfo() { 
    mTypes = new TypeInfo[NUM_TYPES]; 

    // and allocate... 

    // initialize TypeInfos here 
    mTypes[TYPE_CAT].mType = TYPE_CAT; 
    mTypes[TYPE_CAT].mMass = 10.0f; 
    mTypes[TYPE_CAT] ... 

    mTypes[TYPE_ROCK].mType = TYPE_ROCK; 
    ... 
    } 

    public class TypeInfo { 
    public int mType; 
    public int mRawResourceHandle; 
    public float mMass; 
    public Vector2d mDimensions; 
    public float mHealth; 
    public boolean mHasAi; 
    ... 
    } 

    public static final int TYPE_CAT = 0; 
    public static final int TYPE_ROCK = 1; 
    public static final int TYPE_TREE = 2; ... 
    public static final int NUM_TYPES = ???; // the last TYPE_ + 1 

    public TypeInfo mTypes[]; 
} 

Ahora, esto parece como una especie de aplicación XML podría ser la cosa 'correcta' de hacer, pero no estoy seguro acerca de cómo hacer eso (nuevo en Java). De todos modos, las otras clases pueden simplemente usar unitTypeInfo.mTypes [UnitTypeInfo.TYPE_CAT] .mMass (instanciado) para buscar la masa del gato. Sin embargo, si quiero agregar un TYPE_DOG debajo de la definición TYPE_CAT, tengo que actualizar todo debajo (perezoso, lo sé, pero imaginemos que hay algunos tipos más).

Los enum ofrecen una solución fácil a este problema en C++, pero en Java, la solución más simple que puedo hacer ahora requiere algo como: unitTypeInfo.mTypes [UnitTypeInfo.mTypeEnum.TYPE_CAT.ordinal()]. ​​mMass - y aunque supongo que esto no es mucho peor que Mi ya de por sí mala solución, agrega un poco más de indirección y una llamada al método real (a un método que la mayoría de las fuentes no parecen alentar).

Una cosa más es que quiero poder llamar a un interruptor (tipo), por lo que también podría limitar las posibles soluciones.

De todos modos, estoy empezando a tener la idea de que debe haber una solución mucho mejor para todo este problema. ¿Alguna sugerencia?

+2

http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html –

+0

La pregunta relacionada aquí podría ayudar: http://stackoverflow.com/questions/1741708/enum-values-length-vs -private-field – Parappa

+0

No hay razón para tener una matriz de todas las enumeraciones en primer lugar - las enumeraciones de Java son una de sus mejores características que siempre echo de menos en C++/C# donde su azúcar sintáctico solo está alrededor de un "int". Aunque en este caso particular no usaría una enumeración para empezar, sino una clase, parece que la mejor arquitectura (aunque eso puede depender del uso exacto, etc.) – Voo

Respuesta

6

"Classic" java siempre se usa "static final int ANIMAL_CAT = 0;" en casos como este.

JDK 1.5 introducidas "enumeraciones con seguridad de tipos":

http://www.javapractices.com/topic/TopicAction.do?Id=1

Ahora puede hacer esto (una práctica muy común):

enum Quark { 
    /* 
    * These are called "enum constants". 
    * An enum type has no instances other than those defined by its 
    * enum constants. They are implicitly "public static final". 
    * Each enum constant corresponds to a call to a constructor. 
    * When no args follow an enum constant, then the no-argument constructor 
    * is used to create the corresponding object. 
    */ 
    UP, 
    DOWN, 
    CHARM, 
    STRANGE, 
    BOTTOM, 
    TOP 
    } 

O usted puede hacer esto:

/** 
    * Example 2 - adding a constructor to an enum. 
    * 
    * If no constructor is added, then the usual default constructor 
    * is created by the system, and declarations of the 
    * enum constants will correspond to calling this default constructor. 
    */ 
    public enum Lepton { 
    //each constant implicity calls a constructor : 
    ELECTRON(-1, 1.0E-31), 
    NEUTRINO(0, 0.0); 

    /* 
    * This constructor is private. 
    * Legal to declare a non-private constructor, but not legal 
    * to use such a constructor outside the enum. 
    * Can never use "new" with any enum, even inside the enum 
    * class itself. 
    */ 
    private Lepton(int aCharge, double aMass){ 
     //cannot call super ctor here 
     //calls to "this" ctors allowed 
     fCharge = aCharge; 
     fMass = aMass; 
    } 
    final int getCharge() { 
     return fCharge; 
    } 
    final double getMass() { 
     return fMass; 
    } 
    private final int fCharge; 
    private final double fMass; 
    } 

Aquí está la documentación oficial:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html

+1

+1 para la elección del ejemplo. Pero debes tener cuidado, ya que 'Lepton.NEUTRINO' puede viajar más rápido que la luz. – yshavit

+0

Este tipo trabaja en el CERN, simplemente lo sé. – st0le

4

¿Por qué no simplemente esto:

public enum Animal { 
    CAT(4), RAT(4), BAT(4), CHICKEN(2), ..., ANT(6), SPIDER(8); 

    // A simple attribute, like any other java class. 
    // Final to ensure it will never change. 
    private final int legs; 

    // Note that this constructor is private. 
    private Animal(int legs) { 
     this.legs = legs; 
    } 

    // A method, like any other class. 
    public int getLegs() { 
     return legs; 
    } 
} 

Para usarlo:

// How to get all the animals in the enum. 
Animal[] animals = Animal.values(); 

// How to get the number of animals. 
int numAnimals = animals.length; 

// How to get the number of legs of some animal. 
int howManyLegsHaveTheAnt = Animal.ANT.getLegs(); 
int howManyLegsHaveTheFirstAnimal = animals[0].getLegs(); 

// How to get the name of a given animal. 
String theFirstAnimalName = animals[0].name(); // Will return "CAT". 

// How to get the position in the enum of some animal. 
int antPositionInTheEnum = Animal.ANT.ordinal(); 

// How to get an animal given its name. 
Animal rat = Enum.valueOf(Animal.class, "RAT"); 
Animal someAnimal = Enum.valueOf(Animal.class, animalName); 
+0

Gracias por la respuesta, pero puedo haber aludido a una mayor simplicidad de la que pretendía. – jbeck

+0

Java es un lenguaje detallado. La simplicidad en Java no significa un código pequeño. Créelo, este código es simple. Además, leí su edición a la pregunta, que lo convirtió en una pregunta muy diferente, así que publicaré otra respuesta para esto. –

1

En su caso, el uso de enumeraciones no es una buena idea. Los enums son cosas intrínsecamente inmutables, un conjunto fijo donde no se pueden inventar nuevos elementos y no se pueden destruir los elementos existentes. Los días de la semana, los meses del año y los juegos de cartas son un buen ejemplo de enumeraciones, el conjunto existente es fijo e inmutable, nunca se creará ningún elemento nuevo y ningún elemento existente será destruido. Los tipos de animales, géneros musicales, tilesets, etc. no siguen estas reglas.

Cuanto mejor es el más obvio: definir una interfaz o clase abstracta Animal. Y define todos los tipos de animales como un subtipo.

Los interruptores son tan malos como goto, son simples, son fáciles de usar, parecen inocentes, pero al final transforman tu código en una jungla de espagueti. En lugar de usar los interruptores que desee, use polimorfismo. I.E:

// Don't: 
public class SomeClass { 
    public void myMethod() { 
     switch (animal.id) { 
      case TYPE_CAT: 
       doSomethingThatCatDoes(); 
       doSomethingElse(); 
       anotherThing(); 
       break; 

      case TYPE_DOG: 
       bark(); 
       doSomethingThatDogDoes(); 
       otherThing(); 
       break; 
     } 
    } 
} 
// Do: 
public interface Animal { 
    public void myMethodAction(); 
    // Other methods. 
} 

public class Cat implements Animal { 
    @Override 
    public void myMethodAction() { 
     doSomethingThatCatDoes(); 
     doSomethingElse(); 
     anotherThing(); 
    } 
} 

public class Dog implements Animal { 
    @Override 
    public void myMethodAction() { 
     bark(); 
     doSomethingThatDogDoes(); 
     otherThing(); 
    } 
} 

public class SomeClass { 
    public void myMethod() { 
     animal.myMethodAction(); 
    } 
} 

El código tiende a ser mayor cuando se hace esto, pero esto no significa más complejo. En cambio, se organizó mejor, porque SomeClass ya no necesita saber exactamente el tipo de animal. La lógica particular para cada tipo de animal está en un solo lugar, y si necesitas cambiar el comportamiento de un animal, no ganaste ' Necesito buscar y cambiar muchos lugares muy distantes. Además, se vuelve mucho más fácil agregar nuevos tipos de animales. Como debería ver, su proyecto se vuelve más flexible para los cambios futuros (es decir, más fácil de cambiar, más difícil de romper).

Debe tener en cuenta que no utilicé identificadores explícitos. Evita los identificadores, porque son viciosos y ya los tienes implicidad. Cada objeto tiene una dirección de memoria única, y esa dirección de memoria es la identificación. Por lo tanto, su campo public int mType; se convertiría en public Class<? extends Animal> mType;. Si realmente necesita estos identificadores, hágalos tan efímeros como sea posible y los menos utilizados posible. La razón para esto es usar OO beter (explicaré esto a continuación).

Más, su TypeInfo es solo un grupo de atributos públicos. Por favor, nunca, nunca, nunca pienses en hacer esto. En OO, los atributos públicos son tan odiosos como los gotos y los switches, y ELLOS SEGURAMENTE CON EL 100% DE LA PROBABILIDAD socavan su proyecto. En cambio, haga lo que haga para gestionar los campos, coloque la clase TypeInfo y haga que los campos sean privados. Esto no significa reemplazar los atributos públicos por captores y establecedores con muerte cerebral, en su lugar, pon tu lógica de negocios allí.

Le recomiendo encarecidamente que estudie un OO más profundo.Específicamente, encapsulación verdadera (algunas personas dicen que agregar un montón de getters y setters con muerte cerebral está bien, pero no es así, esto no es una verdadera encapsulación). Estudie el polimorfismo, no solo qué es y cómo funciona, sino cómo puede usarlo y por qué. Y lo más importante, estudiar la cohesión y el acoplamiento, para crear clases que tengan sentido, sean bastante independientes, reutilizables y flexibles.

0

Respuesta simple: No Java no tiene enums de tipo C. Aunque lo mismo se puede lograr en Java con una serie de declaraciones como la siguiente:

public static final int GREEN = 1; 
public static final int RED = 2; 
public static final int BLUE = 3; 

Las enumeraciones de Java son diferentes.