たまたまカップ〇ードルが食べたくなった
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はいなくなった…
まあ「”何もしない”をする」ようにしただけですが、関心の分離もできてテストがしやすくなるかと思います。