分岐の多いswitch文やif文は、機能追加や変更がしにくく見通しが悪いです。
機能追加するにはいちいち新たにelse if、case文を増やす必要があり、実装ミスがあると既存に影響を与えてしまう可能性があります。
分岐の多いswitch文やif文はenumですっきり整理できます。
switch文・分岐の多いif文が出てきたら、enumやポリモーフィズムを利用して拡張性を上げることができないかと疑ってみるべきかと思います。
今回はif文とenumを使った場合の比較をしていきます。
目次
例:年齢ごとに異なる料金を返すコードのif/enumの比較
if文の場合
新たな料金枠を追加するにはelse ifブロックを新たに追加する必要があり、さらに複雑になります。
private int getFee(int age) {
if (age >= 0 && age <= 10) {
return 1000;
} else if (age <= 60) {
return 2000;
} else if (age <= 100) {
return 1500;
}
throw new IllegalArgumentException("どの料金体系にも属さない");
}
enumの場合
if文よりコード量が多くなってますが、拡張性・可読性が上がっていると思います。
条件式は一つだけです。新たな料金枠を増やすのも要素を追加するだけです。
また、要素ごとに名前が付けられるので意味や役割を表せるため可読性も向上します。
enum FeeType {
CHILD(0, 10, 1000),
ADULT(10, 60, 2000),
SENIOR(60, 100, 1500)
;
private final int lower;
private final int upper;
private final int fee;
FeeType(int lower, int upper, int fee) {
this.lower = lower;
this.upper = upper;
this.fee = fee;
}
static FeeType fromAge(int age) {
for (FeeType type : FeeType.values()) {
if (type.lower <= age && type.upper <= age) {
return type;
}
}
throw new IllegalArgumentException("どの料金体系にも属さない");
}
}
private int getFee(int age) {
return FeeType.fromAge(age).fee;
}
次はif/enumの拡張性の違いについてみていきましょう。
年齢の枠を追加するときの拡張性の違い
次に、4歳以下なら無料にする処理を追加する場合を考えてみます。
ifの場合
条件式・ブロック作ってという感じの修正です。符号とか実装ミスすると動かなくなります。
private int getFee(int age) {
if (age >= 0 && age <= 4) {
return 0;
} else if (age <= 10) {
return 1000;
} else if (age <= 60) {
return 2000;
} else if (age <= 100) {
return 1500;
}
throw new IllegalArgumentException("どの料金体系にも属さない");
}
enumの場合
既存の要素を少し修正して新たに要素を追加するのみです。
数字の入れ間違いと条件式・ブロック作る場合、数字の入れ間違いの方が当然リスクは少ないです。
enumは要素に名前を付けられるので非常に分かりやすいです。
enum FeeType {
BABY(0, 4, 0),
CHILD(4, 10, 1000),
ADULT(10, 60, 2000),
SENIOR(60, 100, 1500)
;
private final int lower;
private final int upper;
private final int fee;
FeeType(int lower, int upper, int fee) {
this.lower = lower;
this.upper = upper;
this.fee = fee;
}
static FeeType fromAge(int age) {
for (FeeType type : FeeType.values()) {
if (type.lower <= age && type.upper <= age) {
return type;
}
}
throw new IllegalArgumentException("どの料金体系にも属さない");
}
}
private int getFee(int age) {
return FeeType.fromAge(age).fee;
}