コンストラクタで値を抱える enum 列挙型の汎用インターフェース

Java enum 使用でよく列挙名と共にコード値を定義して使用したりする設計は
常套手段の1つである。

public enum Frame {

   Gold(101), Silver(101), Bronz(102);

   private int value;

   private Frame(int value) {
      this.value = value;
   }
   public int getValue(){
      return value;
   }
}

よくあるパターンである。
列挙型の並び、( 0始まり、つまり序数=0)は、ordinal() で取得するが、上のように
抱えるコード値取得メソッドは各 enum定義によるもので普遍的ではない。
汎用的な enumタイプハンドラを作ろうと思ってもこのままではできない。

そこで、コード値の取得メソッドを縛ったインターフェースを用意をする。
また、使いそうなメソッドも用意する。
enum で抱えるコード値のが、int でも String でも許容させるので、
Object getValue(); で取得するものとしている。

循環参照する総称型である。

import java.util.Arrays;
import java.util.Optional;
/**
 * Generic enum Interface
 */
public interface EnumBase<E extends Enum<E>>{

   public Object getValue();

   static <E> E[] getArray(Class<E> clz) {
      return clz.getEnumConstants();
   }

   @SuppressWarnings("unchecked")
   static <E extends Enum<E>> E valueOf(Class<? extends  Enum<E>> cls, String value) {
      return (E)Arrays.stream(cls.getEnumConstants())
            .filter(e->e.name().equals(value))
            .findAny()
            .orElse(null);
   }

   @SuppressWarnings("unchecked")
   static <E extends Enum<E>> Optional<E> parseOf(Class<? extends  Enum<E>> cls, String value) {
      return (Optional<E>) Arrays.stream(cls.getEnumConstants())
            .filter(e->e.name().equals(value))
            .findAny();
   }

   @SuppressWarnings("unchecked")
   static <E extends Enum<E>> Optional<E> parseCode(Class<? extends  EnumBase<E>> cls, Object code) {
      return (Optional<E>) Arrays.stream(cls.getEnumConstants())
            .filter(e->e.getValue().equals(code))
            .findAny();
   }

   @SuppressWarnings("unchecked")
   static <E extends Enum<E>> E codeOf(Class<? extends  EnumBase<E>> cls, Object code) {
      return (E) Arrays.stream(cls.getEnumConstants())
            .filter(e->e.getValue().equals(code))
            .findAny().orElse(null);
   }
}

使用例

public enum Frame implements EnumBase<Frame>{

   Gold(100), Silver(101), Bronz(102);

   private int value;

   private Frame(int value) {
      this.value = value;
   }
   @Override
   public Object getValue(){
      return value;
   }
}
System.out.println("Frame.Gold   getCode()  : " + Frame.Gold.getValue() );

// enum values() と同じ結果を求める

Frame[] frames = EnumBase.getArray(Frame.class);

System.out.println("--- Arrays.stream(frames).forEach(System.out::println); ---");
Arrays.stream(frames).forEach(System.out::println);

System.out.println("---------");
Frame g = Frame.valueOf("Gold");
System.out.println( g +" "+g.getValue() );

System.out.println("--- Frame v = EnumBase.valueOf(Frame.class, \"Silver\"); ---");

Frame v = EnumBase.valueOf(Frame.class, "Silver");
Frame v2 = EnumBase.parseOf(Frame.class, "Silver").orElse(null);

System.out.println("EnumBase<Frame> v  : "+v.name() );
System.out.println("v.equlas(v2)       : "+v.equals(v2) );


Optional<Frame> v102 = EnumBase.parseCode(Frame.class, 102);
System.out.println("EnumBase<Frame> v102  : "+v102.map(o ->o.name()).orElse(null) );

Frame b = EnumBase.codeOf(Frame.class, 101);
System.out.println(b.name());

実行して標準出力されるもの。。。

Frame.Gold   getCode()  : 100
--- Arrays.stream(frames).forEach(System.out::println); ---
Gold
Silver
Bronz
---------
Gold 100
--- Frame v = EnumBase.valueOf(Frame.class, "Silver"); ---
EnumBase<Frame> v  : Silver
v.equlas(v2)       : true
EnumBase<Frame> v102  : Bronz
Silver

この EnumBase を使って enum用タイプハンドラは、
https://oboe2uran.hatenablog.com/entry/2021/03/14/003000