switchとEnumMap

# switch

switchはbyte、short、int型の値やString型の値だけでなく列挙型も式に取れるので、サクッと条件分岐させたいときには便利ですよね。

ただ、その主張が激しくなってくると・・・。

```Java:DayOfWeek列挙体
enum DayOfWeek {
    SUNDAY    ("日曜日"),
    MONDAY    ("月曜日"),
    TUESDAY   ("火曜日"),
    WEDNESDAY ("水曜日"),
    THURSDAY  ("木曜日"),
    FRIDAY    ("金曜日"),
    SATURDAY  ("土曜日");

    private String name;

    private DayOfWeek(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
};
```

```Java:Personクラス
class Person {
    private DayOfWeek dayOfWeek;
    private String lyrics;

    private Person(DayOfWeek dayOfWeek) {
        setDayOfWeek(dayOfWeek);
    }

    // インスタンスを生成するstaticメソッド
    static Person todayIs(DayOfWeek dayOfWeek) {
        return new Person(dayOfWeek).doSometing();
    }
    
    // 曜日を設定するメソッド
    Person setDayOfWeek(DayOfWeek dayOfWeek) {
        Objects.requireNonNull(dayOfWeek, "帰れや");
        this.dayOfWeek = dayOfWeek;
        return this;
    }

    // 何かするメソッド
    Person doSometing() {
        lyrics = dayOfWeek.getName();
        switch (dayOfWeek) {
            case SUNDAY:
                lyrics += "に市場へでかけ";
                break;
            case MONDAY:
                lyrics += "におふろをたいて";
                break;
            case TUESDAY:
                lyrics += "はおふろにはいり";
                break;
            case WEDNESDAY:
                lyrics += "にともだちが来て";
                break;
            case THURSDAY:
                lyrics += "は送っていった";
                break;
            case FRIDAY:
                lyrics += "は糸まきもせず";
                break;
            case SATURDAY:
                lyrics += "はおしゃべりばかり";
                break;
        }
        return this;
    }

    // ギャンブルをするメソッド
    Person gambling(int amount) {
        lyrics = dayOfWeek.getName();
        switch (dayOfWeek) {
            case SUNDAY:
            case TUESDAY:
            case THURSDAY:
            case FRIDAY:
            case SATURDAY:
                lyrics += "に" + amount + "万負けて";
                break;
            case MONDAY:
            case WEDNESDAY:
                lyrics += "に" + amount + "万勝って";
                break;
        }
        return this;
    }

    // テュリャるメソッド
    Person turya() {
        switch (dayOfWeek) {
            case SUNDAY:
                lyrics += "テュリャ";
                break;
            case MONDAY:
                lyrics += "テュリャ　リャ";
                break;
            case TUESDAY:
                lyrics += "テュリャ　テュリャ　テュリャ";
                break;
            case WEDNESDAY:
                lyrics += "テュリャ　テュリャ　テュリャリャ";
                break;
            case THURSDAY:
                lyrics += "、あ？";
                break;
            case FRIDAY:
                lyrics += "てゆりや";
                break;
            case SATURDAY:
                lyrics += "turya";
                break;
            default:
                break;
        }
        return this;
    }

    // 歌うメソッド
    Person sing() {
        System.out.println(lyrics);
        lyrics = "";
        return this;
    }
}
```

このように、くどさがでてきます。
`break`の記述漏れにより予期せぬフォールスルーを生む危険性もでてきます。

```Java:Personクラスの使用例
Person.todayIs(MONDAY).sing()
    .setDayOfWeek(TUESDAY).doSometing().turya().sing()
    .setDayOfWeek(THURSDAY).gambling(100).turya().sing()
    .setDayOfWeek(SATURDAY).doSometing().turya().sing();
```

```:出力
月曜日におふろをたいて
火曜日はおふろにはいりテュリャ　テュリャ　テュリャ
木曜日に100万負けて、あ？
土曜日はおしゃべりばかりturya
```

# EnumMap

列挙体と紐付けてデータを管理できるEnumMapというものがあります。
これを使って書き換えると、

```Java:Personクラス（修正）
class Person {
    ... // フィールドから曜日を設定するメソッドまで省略

    // 何かするメソッド
    Person doSometing() {
        lyrics = dayOfWeek.getName() + SOMETHING_MAP.get(dayOfWeek);
        return this;
    }

    // ギャンブルをするメソッド
    Person gambling(int amount) {
        lyrics = dayOfWeek.getName() + "に" + amount + "万" + GAMBLING_MAP.get(dayOfWeek);
        return this;
    }

    // テュリャるメソッド
    Person turya() {
        lyrics += TURYA_MAP.get(dayOfWeek);
        return this;
    }

    // 歌うメソッド
    Person sing() {
        System.out.println(lyrics);
        lyrics = "";
        return this;
    }

    // EnumMap

    /** 何か */
    private static final EnumMap<DayOfWeek, String> SOMETHING_MAP =
        new EnumMap<>(DayOfWeek.class) {{
            put(SUNDAY, "に市場へでかけ");
            put(MONDAY, "におふろをたいて");
            put(TUESDAY, "はおふろにはいり");
            put(WEDNESDAY, "にともだちが来て");
            put(THURSDAY, "は送っていった");
            put(FRIDAY, "は糸まきもせず");
            put(SATURDAY, "はおしゃべりばかり");
        }};

    /** ギャンブル */
    private static final EnumMap<DayOfWeek, String> GAMBLING_MAP =
        new EnumMap<>(DayOfWeek.class) {{
            final String WIN = "勝って";
            final String LOSE = "負けて";
            put(SUNDAY, LOSE);
            put(MONDAY, WIN);
            put(TUESDAY, LOSE);
            put(WEDNESDAY, WIN);
            put(THURSDAY, LOSE);
            put(FRIDAY, LOSE);
            put(SATURDAY, LOSE);
        }};

    /** テュリャ */
    private static final EnumMap<DayOfWeek, String> TURYA_MAP =
        new EnumMap<>(DayOfWeek.class) {{
            put(SUNDAY, "テュリャ");
            put(MONDAY, "テュリャ　リャ");
            put(TUESDAY, "テュリャ　テュリャ　テュリャ");
            put(WEDNESDAY, "テュリャ　テュリャ　テュリャリャ");
            put(THURSDAY, "、あ？");
            put(FRIDAY, "てゆりや");
            put(SATURDAY, "turya");
        }};
}
```

とりあえず管理はしやすくなった・・・はず。

いまいちコレ！という使いどころに自信がありませんが、列挙体と直接紐付けるデータならば列挙体内で直接定義し、そうでなければ個々のクラスでEnumMapを活用するというような使い方なのでしょうかね[^1]？

[^1]: 今回は後者を想定して（DayOfWeek列挙体を他クラスでも使い回すと仮定して）、列挙体には曜日の名前以外のデータを紐付けませんでした。