как удалить тринокулярный оператор в фильтре потока Java8

Я практикую рефакторинг и 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 ответ
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.

    — дариозицилий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *