EnumとFunctionを組み合わせるとIF分岐が不要になる説

# たまたまカップ〇ードルが食べたくなった
Java7くらいまででまあまあありそうな形式のソース

```java
public class Sample {
	public static void main(String... args) {
		new Noodle(InstantNoodle.CUP_XOODLES).make();
	}
}

@Data
class Noodle {
	private InstantNoodle noodle;
	private int status; // インスタンスを操作してる感を出すために設定してます

	Noodle(InstantNoodle noodle) {
		this.noodle = noodle;
		this.status = 0;
	}

	public void make() {
		System.out.println(noodle.getName() + "を作ります。");
		status = 1;
		if (noodle.isBeforeKayaku()) {
			System.out.println("先入れのかやくを入れます。");
			status = 2;
		}
		if (noodle.isBeforeSauce()) {
			System.out.println("先入れのソースを入れます。");
			status = 3;
		}
		System.out.println("お湯を入れて、" + noodle.getWaitMinutes() + "分間待ちます。");
		status = 4;
		if (noodle.isDiscardWater()) {
			System.out.println("湯切りをします。");
			status = 5;
		}
		if (noodle.isAfterKayaku()) {
			System.out.println("後入れのかやくを入れます。");
			status = 6;
		}
		if (noodle.isAfterSauce()) {
			System.out.println("後入れのソースを入れます。");
			status = 7;
		}
		System.out.println("上手に出来ました！");
		status = 8;
	}

	public boolean canEat() {
		return status == 8;
	}
}

@AllArgsConstractor
@Getter
enum InstantNoodle {
	CUP_XOODLES("カップ〇ードル", false, false, 3, false, false, false);

	private String name;
	private boolean beforeKayaku;
	private boolean beforeSauce;
	private int waitMinutes;
	private boolean discardWater;
	private boolean afterKayaku;
	private boolean afterSauce;
}
```
一連の処理が一連のコードとなって書かれてますね。
こんな単純なIF分岐ならいいですけど、複雑化したらテストしたくないですよね。。。

# 検証してみた
で、Functionを使って書き換えてみたパターン

```java
class Noodle {
	// 他は省略
	public void make() {
		InstantNoodleMaking.OPEN.getFunction() //
				.andThen(noodle.getBeforeKayaku().getFunction()) //
				.andThen(noodle.getBeforeSauce().getFunction()) //
				.andThen(InstantNoodleMaking.WAIT_MINUTE.getFunction()) //
				.andThen(noodle.getDiscardWater().getFunction()) //
				.andThen(noodle.getAfterKayaku().getFunction()) //
				.andThen(noodle.getAfterSauce().getFunction()) //
				.andThen(InstantNoodleMaking.FINISH.getFunction()) //
				.apply(this);
	}
}

@AllArgsConstractor
@Getter
enum InstantNoodle {
	CUP_XOODLES("カップ〇ードル", InstantNoodleMaking.NEEDLESS,
			InstantNoodleMaking.NEEDLESS, 3, InstantNoodleMaking.NEEDLESS,
			InstantNoodleMaking.NEEDLESS, InstantNoodleMaking.NEEDLESS);

	private String name;
	private InstantNoodleMaking beforeKayaku;
	private InstantNoodleMaking beforeSauce;
	private int waitMinutes;
	private InstantNoodleMaking discardWater;
	private InstantNoodleMaking afterKayaku;
	private InstantNoodleMaking afterSauce;
}

@AllArgsConstractor
@Getter
enum InstantNoodleMaking {
	NEEDLESS((e) -> e), //
	OPEN((e) -> {
		System.out.println(e.getNoodle().getName() + "を作ります。");
		e.setStatus(1);
		return e;
	}), //
	BEFORE_KAYAKU((e) -> {
		System.out.println("先入れのかやくを入れます。");
		e.setStatus(2);
		return e;
	}), //
	BEFORE_SAUCE((e) -> {
		System.out.println("先入れのソースを入れます。");
		e.setStatus(3);
		return e;
	}), //
	WAIT_MINUTE((e) -> {
		System.out.println("お湯を入れて、" + e.getNoodle().getWaitMinutes() + "分間待ちます。");
		e.setStatus(4);
		return e;
	}), //
	// 省略
	FINISH((e) -> {
		System.out.println("上手に出来ました！");
		e.setStatus(8);
		return e;
	}), //
	;
	private Function<Noodle, Noodle> function;
}
```
# そしてifはいなくなった…
まあ「”何もしない”をする」ようにしただけですが、関心の分離もできてテストがしやすくなるかと思います。