#java #list
#java #Список
Вопрос:
У меня есть класс Java с 3 логическими свойствами, подобными этому
boolean isActive;
boolean isEnable;
boolean isNew;
каждое свойство связано с перечислением (например, ACTIVE, ENABLE,NEW).
Я хочу иметь 2 списка перечислений. Тот, который имеет только перечисления, связанные с истинным значением свойства, и один для ложного.
просто для ясности. используя оператор if-else, я мог бы
Set<FlagEnum> flagSet = new HashSet<>();
Set<FlagEnum> falseFlagSet = new HashSet<>();
if (object.isActive()) {
flagSet.add(ACTIVE);
} else {
falseFlagSet.add(ACTIVE);
}
if (object.isEnable()) {
flagSet.add(ENABLE);
} else {
falseFlagSet.add(ENABLE);
}
if (object.isNew()) {
flagSet.add(NEW);
} else {
falseFlagSet.add(NEW);
}
есть ли способ избежать всех этих if-else?
Я пытался с чем-то вроде
Map<boolean, List<Pair<boolean, FlagEnum>>> res = Stream.of(
new Pair<>(object.isActive(), ACTIVE),
new Pair<>(object.isNew(), NEW),
new Pair<>(object.isEnable(), ENABLE))
.collect(Collectors.partitioningBy(Pair::getKey));
но полученная структура представляет собой дополнительную сложность, которой я хотел бы избежать.
В моем реальном случае у меня более 15 логических свойств…
Комментарии:
1. Если вы реализовали свое перечисление как an
EnumSet
, вы могли бы немного упростить проблему, выведя вfalseFlagSet
качестве дополнения кtrueFlagSet
(или просто реализуйте свой собственный метод дополнения). Конечно, это не помогает при сопоставлении логической структуры с частью перечисления.
Ответ №1:
Вы можете упростить это различными способами. Какие из них имеют смысл, зависит от ваших точных требований.
- Вы можете получить
falseFlagSet
тривиально изflagSet
usingEnumSet.complementOf
после заполненияflagSet
:EnumSet<FlagEnum> falseFlagSet = EnumSet.complementOf(flagSet);
Предполагается, что все
FlagEnum
значения имеют соответствующие флаги. Если это не так, то вам нужно создать aEnumSet
со всеми перечислениями, у которых есть флаги, и вычестьflagSet
из этого usingremoveAll
. - # 1 уже устраняет необходимость
else
в вашем каскаде, упрощая код доif (object.isActive()) { flagSet.add(ACTIVE); } if (object.isEnable()) { flagSet.add(ENABLE); } if (object.isNew()) { flagSet.add(NEW); }
- Если у вас достаточно разных флагов, вы можете создать сопоставление из метода getter для
FlagEnum
значения, подобного этому:Map<Function<YourClass,Boolean>,FlagEnum> GETTERS = Map.of( YourClass::isActive, FlagEnum.ACTIVE, YourClass::isNew, FlagEnum.NEW, YourClass::isEnable, FlagEnum.ENABLE);
Затем вы можете использовать это, чтобы сделать весь процесс управляемым данными:
EnumSet<FlagEnum> getFlagSet(YourClass yourObject) { EnumSet<FlagEnum> result = EnumSet.noneOf(FlagEnum.class); for (Map.Entry<Function<YourClass,Boolean>, FlagEnum> getter : GETTERS.entrySet()) { if (getter.getKey().apply(yourObject)) { result.add(getter.getValue()); } } return resu< }
- Если количество флагов очень велико, вы можете полностью переключиться на отражение и динамически определять флаги и соответствующие геттеры с помощью сравнения строк, но я бы не стал предлагать такой подход. Если вам нужно что-то подобное, вам, вероятно, следует переключиться на фреймворк, который поддерживает такую функцию, а не реализовывать ее самостоятельно.
Очевидно, что последние два имеют смысл только тогда, когда количество флагов велико. Если на самом деле это всего лишь 3 флага, то я бы не возражал и просто использовал 3 простых if
утверждения.
В качестве небольшого касательного: GETTERS
выше определенно должна быть неизменяемая карта (оберните ее Collections.unmodifiableMap
или используйте что-то вроде Guava ImmutableMap
), и можно утверждать, что то же самое относится и к возвращаемому значению getFlagSet
метода. Я оставил их для краткости.
Ответ №2:
Для этого вы можете использовать частный вспомогательный метод.
private void addFlagSet(boolean condition, FlagEnum flagEnum,
Set<FlagEnum> flagSet, Set<FlagEnum> falseFlagSet) {
Set<FlagEnum> chosenFlagSet = condition ? flagSet: falseFlagSet;
chosenFlagSet.add(flagEnum);
}
Назовите это как:
addFlagSet(object.isActive(), FlagEnum.ACIVE, flagSet, falseFlagSet);
addFlagSet(object.isNew(), FlagEnum.NEW, flagSet, falseFlagSet);
addFlagSet(object.isEnable(), FlagEnum.ENABLE, flagSet, falseFlagSet);
Ответ №3:
Вероятно, вы могли бы использовать отражение для получения всех методов, а затем проверить, есть ли getReturnType() == boolean.class
. Проблема заключается в связи между именем метода и перечислением. Если каждый из них назван как метод без «is», вы можете использовать FlagEnum.valueOf()
для извлечения значения enum из имени метода и использовать его.
Ответ №4:
Я думаю, что это может быть самым простым и понятным способом сделать то, что мне нужно
Map<Boolean, Set<FlagEnum>> flagMap = new HashMap<>();
flagMap.computeIfAbsent(object.isActive(), h -> new HashSet()).add(ACTIVE);
flagMap.computeIfAbsent(object.isEnabled(), h -> new HashSet()).add(ENABLE);
flagMap.computeIfAbsent(object.isNew(), h -> new HashSet()).add(NEW);
//to get TRUE set simply :
flagMap.get(true);
что вы думаете?