概要
このエントリでは、Javaのenumにabstractなメソッドを定義してそれぞれの振る舞いを書くことについて取り扱います。
(EffectiveJava 3rd editionに書いてあるやつ、だいたいそのまんまです。自分でやってみた内容についてメモしておきます。)
Javaのenum
Javaのenumでは、値だけでなくメソッドを定義することができます。
値だけ定義したパターン
enum Operator {
PLUS, SUBTRACT, MULTIPLY, DIVIDE, NONE
}
これに対し、値ごとにメソッドを定義し、下図のような書き方をすることができます。
enum Operator {
PLUS {
@Override
BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
return lhs.add(rhs);
}
},
SUBTRACT{
@Override
BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
return lhs.subtract(rhs);
}
},
MULTIPLY {
@Override
BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
return lhs.multiply(rhs);
}
},
DIVIDE {
@Override
BigDecimal apply(@NonNull BigDecimal lhs, @NonNull BigDecimal rhs) {
return lhs.divide(rhs, BigDecimal.ROUND_UNNECESSARY);//;
}
},
NONE {
// allow null for rhs
@Override
BigDecimal apply(@NonNull BigDecimal lhs, BigDecimal rhs) {
return lhs;
}
};
abstract BigDecimal apply(BigDecimal lhs, BigDecimal rhs);
}
enum内の「abstract BigDecimal apply(BigDecimal lhs, BigDecimal rhs);」ですべての値で定義すべきメソッドを指定しておき、それぞれの値の宣言時にメソッドをOverrideしています。
(補足)上のソースで、「@NonNull」は、lombokで提供されているアノテーションの一つで、Nullチェックを実装してくれるものです。
使用例
前述の形でenumを定義しておくと、例えば以下のようなメソッドが、
public synchronized BigDecimal pushEvalButton() {
var v = new BigDecimal(sb.toString());
switch(currentOperator) {
case PLUS: {
v = stack.add(getCurrentValue());
break;
}
case SUBTRACT: {
v = stack.subtract(getCurrentValue());
break;
}
case MULTIPLY: {
v = stack.multiply(getCurrentValue());
break;
}
case DIVIDE: {
v = stack.divide(getCurrentValue(), BigDecimal.ROUND_UNNECESSARY);//
break;
}
case NONE: {
return v;
}
default: {
throw new RuntimeException("Not defined.");
}
}
currentOperator = Operator.NONE;
replaceBuffer(v.toPlainString());
clearStack();
return v;
}
下記のようにスッキリ書けます。
public synchronized BigDecimal pushEvalButton() {
var v = new BigDecimal(sb.toString());
if(Operator.NONE == currentOperator) {
return v;
}
v = currentOperator.apply(stack, getCurrentValue());
currentOperator = Operator.NONE;
replaceBuffer(v.toPlainString());
clearStack();
return v;
}
enumのメソッドの方に内容が移動したので元のメソッドからコードが減るのは当然として、以下がメリットと感じました。
- switch内のdefaultを追い出せた
- ほかの場所でもenumのメソッドを使うことにより、処理が一か所にまとめられた
まとめ
このエントリでは、Javaのenumにabstractなメソッドを定義してそれぞれの振る舞いを書くことについて、例をあげて説明しました。
上記の差分例は、GitHubのこのcommitを参照ください。