はじめに
この記事では、Enum(列挙)型と同じふるまいをするコードをEnum型を用いない形で表現します。
JavaのEnum(列挙)型は、複数の定数をひとまとめにしておく型のことです。血液型や性別、月の名前、星座、様々なコードなどの決まった定数の集まりをオブジェクト指向の考え方に基づいてコードにすることができます。加えて、便利な関数をデフォルトで使用することができます。
今回は、トランプのマーク(スペード、ハート、ダイヤ、クラブ)を例に説明します。
Enum型を使用した場合
public enum Suit {
SPADE("♠"), HEART("♡"), DIAMOND("♢"), CLUB("♣");
private String symbol;
private Suit(String symbol){
this.symbol = symbol;
}
public String getSymbol(){
return symbol;
}
}
Enum型を使用しない場合
public class Suit implements Comparable<Suit>{
public static final Suit SPADE = new Suit("SPADE", "♠");
public static final Suit HEART = new Suit("HEART", "♡");
public static final Suit DIAMOND = new Suit("DIAMOND", "♢");
public static final Suit CLUB = new Suit("CLUB", "♣");
private static final List<Suit> VALUES =
Collections.unmodifiableList(
Arrays.asList(SPADE, HEART, DIAMOND, CLUB)
);
private final String name;
private final String symbol;
private Suit(String name, String symbol){
this.name = name;
this.symbol = symbol;
}
public String getSymbol(){
return symbol;
}
@Override
public int compareTo(Suit t){
return Integer.valueOf(this.ordinal()).compareTo(t.ordinal());
}
public Class<? extends Suit> getDeclaringClass(){
return this.getClass();
}
public String name(){
return name;
}
public int ordinal(){
return VALUES.indexOf(this);
}
@Override
public String toString(){
return name();
}
public static Suit valueOf(String name){
for(Suit value : VALUES){
if(value.name.equals(name)) return value;
}
throw new IllegalArgumentException();
}
public static List<Suit> values() {
return VALUES;
}
}
解説
コメントをたくさんいただいたので、2018/03/06 に追記しました。
メンバ変数 VALUES
List 部分は、このように書かれています。
private static final List<Suit> VALUES =
Collections.unmodifiableList(
Arrays.asList(SPADE, HEART, DIAMOND, CLUB)
);
この部分は、メンバ変数 VALUES に4つのマーク(Suit)を要素とした不変リストを代入しています。それぞれの関数について解説します。
- Collections.unmodifiableList 関数は、不変リストを戻り値とします。不変リストは、ArrayList のような可変リストと異なり、値を変更することができません。
- Arrays.asList 関数は、引数を要素とした List を戻り値とします。この関数を介することで、List に初期値を代入することができます。今回は使用しませんが、戻り値の List の size(要素数)を増やしたり減らしたりすることはできません。この List は固定リストだからです。
※ Enum 型では、values 関数の戻り値は配列です(今回の場合は、Suit[])。ですが、勉強のためにList 型を戻り値としています。
コンストラクタの引数
Enum 型を使用した場合と、
private Suit(String symbol)
使用しない場合で、
private Suit(String name, String symbol)
コンストラクタの引数が異なっています。その理由は、toString 関数やvalueOf 関数で用いるメンバ変数の変数名(値はそれぞれ文字列の SPADE, HEART, DIAMOND, CLUB)を、関数を用いて取得する方法がないためです。そのため、引数を介してクラスに保持させておく必要があります。
参考資料
[新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES) ](固定リンク: http://amzn.asia/c5WxOUh)