白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

インタフェースのデフォルト実装を使えばenumに共通メソッドを作れるんじゃないの?って話

しばらくPlayFrameworkについて書いてましたが、たまには別のテーマを。


Javaenumはなかなかに便利なのに、あまり使っているのを見掛けないのは何故なのだろう。
SingletonパターンやStateパターンなんかにはなかなか良いような気がするのだけれど。

ただこのenum、暗黙的にEnumクラスを実装しているので継承ができないというのが意外にネック。
となると複数enumに共通処理を書く場合って、enumの外側にユーティリティ的に作るしかない。


たとえば、列定義からExcelのアドレスが取りたいとかいうと、こんなことになる。

interface ExcelColEnum {
}

enum ColDef implements ExcelColEnum {

	NO
	, NAME
	, TANKA
	, SURYO
	, KINGAKU
	;
}

class Util {
	public static <T extends Enum<T> & ExcelColEnum> String getColAlpha(T def) {
		return String.valueOf((char)('A' + def.ordinal()));
	}
	public static <T extends Enum<T> & ExcelColEnum> String getAddress(T def, int row) {
		return getColAlpha(def) + row;
	}
}

マーカーインタフェースを作って境界を作り、列挙型を引数に受けて戻り値を返す形。
当然呼び方はこうなる。

Util.getAddress(ColDef.NAME, 3)

違うんだ。そうじゃないんだ。
こう呼びたいんだ。

ColDef.NAME.getAddress(3)


ということで、java8ならインタフェースのデフォルト実装があるから書けるんじゃないかと思って試してみる。

interface ExcelColEnum {

	default String getColAlpha() {
		return String.valueOf((char)(this.getStartCol() + this.ordinal()));
	}

	default String getAllress(int row) {
		return this.getColAlpha() + row;
	}

	default char getStartCol() {
		return 'A';
	}

	public int ordinal();
}

む・・・。
親インタフェースにordinalを定義しているEnumを指定したいが、これはクラスだからできない。
というわけで直接ordinalを定義してしまったが、これは許されるんだろうか。

ついでに開始列とかもOverrideできるようにしてみた。

結構使いやすそうな気はするけどどうかな。