Я практикую рефакторинг и Java 8 с очень простыми примерами Powerball.
Я использовал перечисление LottoRank, чтобы написать функцию, которая возвращает соответствующий LottoRank на основе количества совпадений и бонусных шаров.
1-е место — это когда вы выпали все 6 номеров.
2-е место — когда вы забиваете 5 бонусным шаром.
3-е место — когда вы набираете 5 без бонусного шара.
4-е место — когда вы выпадаете 4 числа.
5-е место — когда вы выпадаете 3 числа.
Логика получения этого значения следующая.
- LottoRank
NONE(Integer.MIN_VALUE, 0),
FIFTH(3, 5000),
FOURTH(4, 50000),
THIRD(5, 1500000),
SECOND(5, 30000000),
FIRST(6, 2000000000);
private final int matchCount;
private final Money winnerMoney;
LottoRank(int matchCount, int winnerMoney) {
this.matchCount = matchCount;
this.winnerMoney = new Money(winnerMoney);
}
public boolean isCorrectMatchCount(int matchCount) {
return this.matchCount == matchCount;
}
public int calculateWinningMoney(Integer value) {
return winnerMoney.multiple(value);
}
public static LottoRank findRank(String winnerRank) {
return LottoRankPredicates.filterLottoRankWithString(winnerRank);
}
public static LottoRank valueOf(int matchCount, boolean bonusBall) {
return Arrays.stream(LottoRank.values())
.filter(rank -> isThirdOrSecond(matchCount) ?
filterIsSecond(bonusBall, rank.winnerMoney) : rank.matchCount == matchCount)
.findAny()
.orElse(LottoRank.NONE);
}
private static boolean isThirdOrSecond(int matchCount) {
return matchCount == LottoRank.THIRD.matchCount;
}
private static boolean filterIsSecond(boolean bonusBall, Money winnerMoney) {
return bonusBall ? winnerMoney.equals(LottoRank.SECOND.winnerMoney) : winnerMoney.equals(LottoRank.THIRD.winnerMoney);
}
public static LottoRank matches(List<Number> winningNumbers, List<Number> holdingLottoNumbers, Number bonusBall) {
int matchCount = Math.toIntExact(winningNumbers.stream()
.filter(holdingLottoNumbers::contains)
.count());
boolean isSecond = holdingLottoNumbers.contains(bonusBall);
return LottoRank.valueOf(matchCount, isSecond);
}
Если вы посмотрите на фильтрующую часть valueOf()
, вы определите, является ли он 2-м или 3-м (т. е. вы получили 5 правильных ответов). В зависимости от того, был ли поражен бонусный шар, логика обновляется до 2-го места, и если нет, рейтинг обрабатывается в соответствии с правильным номером.
Я хочу стереть трехчленный оператор в этой части.
Однако операторы else и операторы switch-case не допускаются.
Я подумал о префиксе или нескольких фильтрах, но в конечном итоге первое условие должно быть правильным для выполнения следующего условия, и этот код будет сгенерирован.
Это код, который не работал должным образом, но он такой.
public static LottoRank valueOf(int matchCount, boolean bonusBall) {
return Arrays.stream(LottoRank.values())
.filter(rank -> matchCount == rank.matchCount)
.filter(rank -> isThirdOrSecond(matchCount))
.filter(rank -> filterIsSecond(bonusBall, rank.winnerMoney))
.findAny()
.orElse(LottoRank.NONE);
}
Есть ли способ переоборудовать это еще?
Отредактировано
Я думал об этом и обработал это с помощью LottoRankPredicates
класс, как показано ниже.
Интересно, что вы думаете о таком рефакторинге?
- LottoRankПредикаты
public class LottoRankPredicates {
private static Predicate<LottoRank> isSecondOrThird(boolean bonusBall) {
return rank -> getSecondOrThird(bonusBall, rank);
}
private static Predicate<LottoRank> defaultCase(int matchCount) {
return rank -> rank.isCorrectMatchCount(matchCount);
}
private static Predicate<LottoRank> findRank(String winnerRank) {
return rank -> rank.name().equals(winnerRank);
}
private static boolean getSecondOrThird(boolean bonusBall, LottoRank rank) {
if(bonusBall) {
return rank == LottoRank.SECOND;
}
return rank == LottoRank.THIRD;
}
public static LottoRank filterLottoRankWithString(String winnerRank) {
return Arrays.stream(LottoRank.values())
.filter(findRank(winnerRank))
.findAny()
.orElseThrow(IllegalArgumentException::new);
}
public static LottoRank filterLottoRankIsSecondOrThird(boolean bonusBall) {
return Arrays.stream(LottoRank.values())
.filter(isSecondOrThird(bonusBall))
.findAny()
.orElse(LottoRank.NONE);
}
public static LottoRank filterLottRankIsDefault(int matchCount) {
return Arrays.stream(LottoRank.values())
.filter(defaultCase(matchCount))
.findAny()
.orElse(LottoRank.NONE);
}
}
- LottoRank
public static LottoRank findRank(String winnerRank) {
return LottoRankPredicates.filterLottoRankWithString(winnerRank);
}
public static LottoRank valueOf(int matchCount, boolean bonusBall) {
if(isThirdOrSecond(matchCount)) {
return LottoRankPredicates.filterLottoRankIsSecondOrThird(bonusBall);
}
return LottoRankPredicates.filterLottRankIsDefault(matchCount);
}
private static boolean isThirdOrSecond(int matchCount) {
return matchCount == LottoRank.THIRD.matchCount;
}
1 ответ
Константы enum
являются полнофункциональные классы. Это означает, что в любой из этих констант вы можете переопределить любой не закрытый метод enum
класс и измените поведение на что-то постоянное и конкретное. В основном это лучшая практика OO обменное ветвление с наследованием.
Итак, подход заключался бы в том, чтобы сделать filterIsSecond()
нестатический и добавить переопределение в константах SECOND
и THIRD
нравится:
(ВНИМАНИЕ! Мой рефакторинг может быть семантически некорректным, поскольку вы не предоставили sscce ни юнит-тестов.)
// ...
THIRD(5, 1500000){
@Overrode
boolean filterIsSecond(boolean bonusBall, Money winnerMoney) {
return bonusBall && this.winnerMoney==winnerMoney;
}
},
SECOND(5, 30000000){
@Overrode
boolean filterIsSecond(boolean bonusBall, Money winnerMoney) {
return this.winnerMoney==winnerMoney;
}
},
FIRST( //..
boolean filterIsSecond(boolean bonusBall, Money winnerMoney) {
return this.matchCount == matchCount;
}
public static LottoRank valueOf(int matchCount, boolean bonusBall) {
return Arrays.stream(LottoRank.values())
.filter(rank -> rank.filterIsSecond(bonusBall, rank.winnerMoney))
.findAny()
.orElse(LottoRank.NONE);
}
Кроме того, вы должны следовать соглашениям об именах Java, которые продвигают методы (которые вы вызываете функции), должны начинаться с глагол или в случае, если они вернутся boolean
(как в вашем случае) shoudl начать с is
, can
, has
или подобное. Таким образом код, который их использует, читается намного лучше.
Здравствуйте, есть опечатка @Overrode.
— дариозицилий