LoginSignup
6
6

More than 3 years have passed since last update.

【Java】if文による条件分岐よりもEnumを使った"設定"を-Strategy Enum

Last updated at Posted at 2019-10-12

if文による条件分岐の複雑さ

ある日が過去・現在・未来なのか判定し、それに応じて処理を分けるとします。これをif文を使って実装すると以下のようなコードになります。実際、この程度ならば見通しがそこまで悪いわけではありませんが、更に細かく条件を分けようとすると、複雑な分岐を読み解く必要があります。

Main.java
public static void main(String[] args) {    
    //変数:pastの時制を判定したい
    LocalDate past =  LocalDate.of(2019, 10, 11);

    LocalDate today = LocalDate.now();  //現在は(2019-10-12)
        if(past.isBefore(today)) {
            System.out.println("Past");
        } 
        if(past.isEqual(today)) {
            System.out.println("Today");
        }
        if(past.isAfter(today)) {
            System.out.println("After");
        }
    //出力: Past
}

「if文による条件分岐」よりも「条件-処理をまとめた設定」を

Strategy Enumを使うと、条件とそれに応じた処理を1対1で記述することができます。

まず、Enum(DatePattern)のフィールドに次の関数型インターフェイスを2つ定義します
 1. 条件: Predicate
 2. 処理: Runnnable

次に、ここではEnumのクラスメソッド of()として、Factory Methodを記述します。Factory Methodは引数で受け取った日付から時制を判定し、それに応じた処理を引き当て、返り値として返却します。

このようにすると、条件と処理を設定 として記述できます。

DatePattern.java
public enum DatePattern {
    //(条件, 処理)の設定
    Past(date -> isBeforeToday(date), () -> System.out.println("Past")),
    Today(date -> isSameToday(date), () -> System.out.println("Today")),
    Future(date -> isAfterToday(date), () -> System.out.println("Future"));

    private final Predicate<LocalDate> dateValidator; //条件
    private final Runnable function; //処理

    //Enumのコンストラクタ
    DatePattern(Predicate<LocalDate> dateValidator, Runnable function) {
        this.dateValidator = dateValidator;
        this.function = function;
    }

    /* Factory Method 
     * 引数のLocal Dateの時制をフィールドで定義した条件(Predicate)で判定して、
     * 処理(Runnnable)を返却する
    */ 
    public static Runnable of(LocalDate date) {
        Optional<Runnable> pattern = Stream.of(DatePattern.values())
                .filter(e -> e.dateValidator.test(date))
                .map(e -> e.function)
                .findFirst();
        return Optional.ofNullable(pattern.get()).orElseThrow(IllegalArgumentException::new);
    }

    // 過去かどうかの判定
    private static boolean isBeforeToday(LocalDate date) {
        LocalDate today = LocalDate.now();
        return date.isAfter(today);
    }
    // 未来かどうかの判定
    private static boolean isAfterToday(LocalDate date) {
        LocalDate today = LocalDate.now();
        return date.isBefore(today);
    }
    // 現在かどうかの判定
    private static boolean isSameToday(LocalDate date) {
        LocalDate today = LocalDate.now();
        return date.equals(today);
    }    
}

Enumを使った結果、以下のようにif文を消すことができます。条件分岐が無いため、見通しを良くすることができました。また、更に細かい判定条件を追加しても、このDatePatternの呼び出し元に影響はありません。
if文による条件分岐を次々に繰り返すのではなく、 Enumに条件と処理をワンセットにして設定 する方が個人的に見通しが高く、保守性が高まると考えています。

Main.java
public static void main(String[] args) {
    LocalDate past =  LocalDate.of(2019, 10, 11);  //過去
    LocalDate today = LocalDate.of(2019, 10, 12);  //現在(2019-10-12)
    LocalDate future = LocalDate.of(2019, 10, 13); //未来

    Runnable past_function = DatePattern.of(past);
    Runnable today_function = DatePattern.of(today);
    Runnable futute_function = DatePattern.of(future);

    past_function.run();
    // 出力: Past
    today_function.run();
    // 出力: Today
    futute_function.run();
    // 出力: Future
}
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6