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


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

```java: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)のフィールドに次の関数型インターフェイスを２つ定義します
　1. 条件: Predicate 
　2. 処理: Runnnable 

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

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

``` java: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に条件と処理をワンセットにして設定** する方が個人的に見通しが高く、保守性が高まると考えています。


``` java: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
}
```