enumに振舞を持たせる

表題のまんまなんだけどその場限りで済んでしまうような場合はこんなんでいいと思うんよね。

/**
 * なんかの種別を表す。
 */
enum Kind {
    A {
        public Result apply(Param param) {
            // Aのばあい
        }
    },

    B {
        public Result apply(Param param) {
            // Bのばあい
        }
    },

    C {
        public Result apply(Param param) {
            // Cのばあい
        }
    };

    /**
     * 指定の引数を元になんかの処理して結果を返す。
     * @param param なんか引数
     * @return 実行結果
     */
    public abstract Result apply(Param param);

}

ただ、複数個所でそれぞれ別のことをしたい場合なんかはその時点で種別と振舞は分けるべきじゃね?っていう。でも同じ機構は利用したいよね。毎度switchとかするのもやだし。ってなわけで↓なんてどうでしょ?

/**
 * なんかの種別を表す。
 */
public enum Kind {
    A,

    B,

    C;

    /**
     * 指定の関数の実行結果を返す。
     * @param <P> 指定の関数に渡す引数の型
     * @param <R> 指定の関数が返す結果の型
     * @param <E> 指定の関数で発生する例外の型
     * @param func 適用する関数
     * @param param 関数に渡す値
     * @return 関数の実行結果(省略可)
     * @throws E 関数の実行中に例外が発生した場合
     * @throws NullPointerException 引数に{@code null}が指定された場合
     */
    public <P, R, E extends Throwable> R apply(Function<P, R, E> func, P param)
            throws E {
        if (func == null) {
            throw new NullPointerException("func"); //$NON-NLS-1$
        }
        switch (this) {
        case A:
            return func.caseOfA(param);
        case B:
            return func.caseOfB(param);
        case C:
            return func.caseOfC(param);
        default:
            throw new AssertionError();
        }
    }

    /**
     * {@link Kind}に適用する関数。
     * @param <P> 引数の型
     * @param <R> 戻り値の型
     * @param <E> 例外の型
     */
    public interface Function<P, R, E extends Throwable> {

        /**
         * {@linkKind#C}に対する処理を行う。
         * @param p 引数
         * @return 実行結果
         * @throws E この処理中に例外が発生した場合
         */
        R caseOfA(P p) throws E;

        /**
         * {@link Kind#B}に対する処理を行う。
         * @param p 引数
         * @return 実行結果
         * @throws E この処理中に例外が発生した場合
         */
        R caseOfB(P p) throws E;

        /**
         * {@linkKind#C}に対する処理を行う。
         * @param p 引数
         * @return 実行結果
         * @throws E この処理中に例外が発生した場合
         */
        R caseOfC(P p) throws E;
    }
}


と、ここまで書いてそういえばid:ashigeruが解説してたようなーと思ってみたらやっぱりあったよorzで、でも別にぱくりじゃないんだからね!

そんなid:ashigeruの記事はこちら。

http://d.hatena.ne.jp/ashigeru/20090119/1232365391
http://d.hatena.ne.jp/ashigeru/20090116/1232109854