LoginSignup
1
1

More than 3 years have passed since last update.

Javaのenumにabstractなメソッドを定義してそれぞれの振る舞いを書く

Last updated at Posted at 2019-12-15

概要

このエントリでは、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を参照ください。

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