前回の続き
vermeer.hatenablog.jp
前回のEnumのようにテーブル値と表記がペアとなっているものは
Interfaceを持たせて共通に操作する仕組みを作成しておくと便利です。
Enumクラスにメソッドを追加
package com.mycompany.samples.enumclass; import lombok.NonNull; public enum GenderNoLombok { MALE(1, "男"), FEMALE(2, "女"); private final int code; private final String property; private GenderNoLombok(int code, String property) { this.code = code; this.property = property; } public int getCode() { return code; } public String getProperty() { return property; } public static GenderNoLombok codeOf(int code) { for (GenderNoLombok enumClass : values()) { if (enumClass.getCode() == code) { return enumClass; } } throw new IllegalArgumentException(); } public static GenderNoLombok propertyOf(@NonNull String property) { for (GenderNoLombok enumClass : values()) { if (enumClass.getProperty().equals(property)) { return enumClass; } } throw new IllegalArgumentException(); } }
シンプルに実装すれば、こんな感じになると思います。
Interfaceもいりません。
これはこれでシンプルで良いと思いますし、嫌いではないです。*1
ただ、すべてのEnumクラスに同じような記述しないといけないので冗長です。
Interfaceとユーティリティを作成
Interface
package com.mycompany.samples.enumclass; public interface EnumCodePropertyInterface { public Object getCode(); public String getProperty(); }
Enumクラス
共通操作が出来るようにInterfaceをimpliment
package com.mycompany.samples.enumclass; import lombok.AllArgsConstructor; import lombok.Getter; @AllArgsConstructor @Getter public enum Gender implements EnumCodePropertyInterface { MALE(1, "男"), FEMALE(2, "女"); private final Integer code; private final String property; }
ユーティリティ
implimentしたInterfaceに合わせた操作を実装
今回は、code値/property値、それぞれの値から、その値とペアになるEnumクラスを生成するstaticメソッドを作成しました。
また、code値については、テーブル定義に左右されるのでObjectにしています。
もし型安全にするのであれば、想定する型のメソッドを準備してオーバーロードしておけば良いと思います。
propertyは明らかに文字列だけということでString固定にしています。
package com.mycompany.samples.enumclass; import lombok.NonNull; public class EnumCodeProperty { public static <E extends Enum<E> & EnumCodePropertyInterface> E codeOf(Class<E> enumType, @NonNull Object code) { for (E type : enumType.getEnumConstants()) { if (type.getCode().equals(code)) { return type; } } throw new IllegalArgumentException(); } public static <E extends Enum<E> & EnumCodePropertyInterface> E propertyOf(Class<E> enumType, @NonNull String property) { for (E type : enumType.getEnumConstants()) { if (type.getProperty().equals(property)) { return type; } } throw new IllegalArgumentException(); } }
実行コード
package com.mycompany.samples.enumclass; import lombok.NoArgsConstructor; @NoArgsConstructor public class EnumTest { public void execUtil() { GenderNoLombok genderNoLombok = GenderNoLombok.codeOf(GenderNoLombok.MALE.getCode()); System.out.println("genderNoLombok.getCode() = " + genderNoLombok.getCode()); System.out.println("genderNoLombok.getProperty() = " + genderNoLombok.getProperty()); genderNoLombok = GenderNoLombok.propertyOf(GenderNoLombok.FEMALE.getProperty()); System.out.println("genderNoLombok.getCode() = " + genderNoLombok.getCode()); System.out.println("genderNoLombok.getProperty() = " + genderNoLombok.getProperty()); Gender gender = EnumCodeProperty.codeOf(Gender.class, Gender.MALE.getCode()); System.out.println("gender.getCode() = " + gender.getCode()); System.out.println("gender.getProperty() = " + gender.getProperty()); gender = EnumCodeProperty.propertyOf(Gender.class, Gender.FEMALE.getProperty()); System.out.println("gender.getCode() = " + gender.getCode()); System.out.println("gender.getProperty() = " + gender.getProperty()); } }
実行結果
genderNoLombok.getCode() = 1 genderNoLombok.getProperty() = 男 genderNoLombok.getCode() = 2 genderNoLombok.getProperty() = 女 gender.getCode() = 1 gender.getProperty() = 男 gender.getCode() = 2 gender.getProperty() = 女
最後に
Enumが通常のクラスであればInterfaceではなく抽象クラスで今回と同様の操作を実装できるかもしれませんがEnumは継承をさせることが出来ません。
そういった技術的な側面もありますが、Enumは定数定義のためのクラスとして、あまり多くの事をしすぎないというのも、1つの整理なのかなぁと思ったりもします。*2
この「Interface+ユーティリティ」のやり方は、Enumだけでなく、リファクタリングをしているときに個人的によく使っています。
ユーティリティで実装の集約を一旦した上で、主語と述語を整理しユーティリティからクラスに格上げをする、というやり方をしています。ロジックだけを見たら似ている気がしたけど概念で考えると違ったり、ユーティリティで汎用的な実装へリファクタリングをしている中で、同分類とすべきドメインが見つかって更に見直しを深めるということは結構ありました。
次は、このEnumクラスを使って、JSFのSelectItemについて汎用的な部品クラスの作成について整理してみたいと思います。*3
追記:2017/1/2
EnumのInterfaceに共通処理を実装してみました。
vermeer.hatenablog.jp