TypeSafeEnumを知る

定数を管理するときの話。
昔は定数クラスとか作ってゴリゴリ書いてたけど、可読性も悪いし、管理も大変だった。
なので、java5からあるenumを使ってみたが、継承が出来ないので、使い勝手が悪かった。。

そんなときに、TypeSafeEnumを知ったので、自分なりに書いてみた。

TypeSafeEnumクラス

/**
 * TypeSafeEnumを作ってみる
 */
public class TypeSafeEnum {

    /**
     * NULL
     */
    public static final TypeSafeEnum NULL = new TypeSafeEnum(null);

    /**
     * Enumマップ
     */
    protected static final Map<String, Object> ENUM_MAP = new HashMap<String, Object>();

    /**
     * 区分値
     */
    private String value;

    /**
     * コンストラクタ
     * @param value 区分値
     */
    protected TypeSafeEnum(String value) {
        this.value = value;
    }

    /**
     * 区分値を取得する
     * @return 区分値
     */
    public String value() {
        return value;
    }

    /**
     * NULL値かどうか
     * @return true:NULL値、false:NULL値でない
     */
    public boolean isNull() {
        return this == NULL;
    }

    /**
     * 区分値からインスタンスを取得する
     * @param <T> {@link TypeSafeEnum}を継承したクラス
     * @param value 区分値
     * @return インスタンス
     */
    @SuppressWarnings("unchecked")
    public static <T extends TypeSafeEnum> T valueof(String value) {
        if (!ENUM_MAP.containsKey(value)) {
            return (T) NULL;
        }
        return (T) ENUM_MAP.get(value);
    }

    /**
     * 区分値のリストを取得する<br>
     * @param <T> {@link TypeSafeEnum}を継承したクラス
     * @return 区分値のリスト
     */
    @SuppressWarnings("unchecked")
    public static <T extends TypeSafeEnum> List<T> values() {
        List<T> enumList = new ArrayList<T>();
        for (Entry<String, Object> enumEntry : ENUM_MAP.entrySet()) {
            enumList.add((T) enumEntry.getValue());
        }
        return enumList;
    }
}

TypeSafeEnumを継承した区分値クラス

/**
 * 血液型区分
 */
public class BloodType extends TypeSafeEnum {

    /**
     * A型
     */
    public static final BloodType A = new BloodType("A型");

    /**
     * B型
     */
    public static final BloodType B = new BloodType("B型");

    /**
     * O型
     */
    public static final BloodType O = new BloodType("O型");

    /**
     * AB型
     */
    public static final BloodType AB = new BloodType("AB型");

    /**
     * コンストラクタ
     * @param value 区分値
     */
    private BloodType(String value) {
        super(value);
    }

    /**
     * 区分値マップを初期化
     */
    static {
        ENUM_MAP.put("A型", A);
        ENUM_MAP.put("B型", B);
        ENUM_MAP.put("O型", O);
        ENUM_MAP.put("AB型", AB);
    }

    /**
     * A型であるかどうか
     * @return true:A型、false:A型でない
     */
    public boolean isA() {
        return this == A;
    }

    /**
     * B型であるかどうか
     * @return true:B型、false:B型でない
     */
    public boolean isB() {
        return this == B;
    }

    /**
     * O型であるかどうか
     * @return true:O型、false:O型でない
     */
    public boolean isO() {
        return this == O;
    }

    /**
     * AB型であるかどうか
     * @return true:AB型、false:AB型でない
     */
    public boolean isAB() {
        return this == AB;
    }

}

なるべく継承クラスには、区分値の定義のみをさせるようにした。
まだまだ、改良の余地はあるがとりあえず版。。