Перечисления Java: сбор информации из других перечислений - PullRequest
3 голосов
/ 24 марта 2010

Я сделал похожий вопрос несколько дней назад, но теперь у меня есть новые требования и новые задачи =). Как обычно, я использую перечисления животных для дидактических целей, когда я не хочу объяснять предметно-ориентированные вещи

У меня есть базовое перечисление животных, которое используется всем зоопарком (я могу добавить к нему что-то, но я должен сохранить совместимость):

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

Мне нужно разделить их на несколько не связанных между собой категорий, таких как серые животные (кит (мой кит серый) и слон), мелкие животные (птица, креветка и собака), морские животные (кит и креветка).

Я мог бы, как предлагалось в моих предыдущих вопросах, добавить много логических значений, таких как isGray, isSmall и isFromSea, но я бы хотел подход, в котором я мог бы хранить это где-то еще (так что мой enum не должен знать много). Что-то вроде:

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

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

Где-то еще

public enum GrayAnimal {
  WHALE,
  ELEPHANT;
}

Как это возможно? Я слишком много запрашиваю у Java?

Ответы [ 6 ]

8 голосов
/ 24 марта 2010

Вы пробовали EnumSet или EnumMap ?

Вы можете создать метод

Set<Animal> grayAnimals(){
   return EnumSet.of(Animal.WHALE, Animal.ELEPHANT);
}
2 голосов
/ 24 марта 2010

Я думаю, что было бы лучше хранить такие свойства в самих экземплярах enum, т.е.

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));
}
1 голос
/ 24 марта 2010

Помните, что перечисления полезны только тогда, когда вам нужно различать объекты в вашем коде - они бесполезны, за исключением того, что они могут быть напечатаны как код.

Это важно, потому что вы вводите в свое программное обеспечение элементы, которые в долгосрочной перспективе окажутся неприятными запахами кода.

Например, как вы используете их, за исключением таких утверждений, как:

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

Это должно немедленно предупредить любого программиста OO - коммутаторы плохо пахнут кодом, поскольку они почти всегда указывают на плохой дизайн OO).

Альтернативой является создание конечного набора объектов, инициализированных данными, предпочтительно не кодом.

Возможно, у вас есть экземпляр critter с атрибутами кита - возможно, whale.move () будет использовать экземпляр WaterMovement, тогда как слон содержит и использует экземпляр LandMovement.

В целом, программирование в ОО вместо использования переключателей и перечислений приведет к колоссальному объему кода.

Каждый раз, когда вы пишете метод, помните мантру «Не спрашивайте у объекта данные, а затем оперируйте объектом, вместо этого попросите объект выполнить за вас операцию».

0 голосов
/ 24 марта 2010

Я думаю, что лучше не загрязнять ваше перечисление такой категоризацией. Лучше всего отделить категории от перечисления, чтобы вы могли добавить больше позже, не затрагивая ваше перечисление. Это следует за разделением интересов и принципом единой ответственности за дизайн класса.

Чтобы сделать это, просто используйте 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 голосов
/ 24 марта 2010

может быть что-то вроде этого:

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);
        }
    }
}
0 голосов
/ 24 марта 2010

Я не знаю, почему вы хотите поместить его в другое перечисление, когда вы можете поместить его в эту функцию:

public boolean isGray() {
     return this == WHALE || this == ELEPHANT;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...