0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-11-30

たまたまカップ〇ードルが食べたくなった

Java7くらいまででまあまあありそうな形式のソース

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を使って書き換えてみたパターン

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はいなくなった…

まあ「”何もしない”をする」ようにしただけですが、関心の分離もできてテストがしやすくなるかと思います。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?