やりたいこと
こんなかんじのフラグのセットを受け取って
boolean useSaba = true;
boolean useTori = false;
boolean useNira = false;
boolean isOomori = true;
マッチするEnumオブジェクトを取得したい。
(上のフラグの場合は LunchSet.SABA_DAI
)
enum LunchSet {
GOHAN("ご飯セット"),
SABA("サバ味噌定食"),
TORI("トリ唐揚定食"),
NIRA("ニラ炒め定食"),
GOHAN_DAI("ご飯セット大盛り"),
SABA_DAI("サバ味噌定食大盛り"),
TORI_DAI("トリ唐揚定食大盛り"),
NIRA_DAI("ニラ炒め定食大盛り");
private final String name;
private LunchSet(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
方法1 ビット演算
- Enumのコンストラクタにビット演算用の数値を追加する。
- 数値を元にマッチするEnumオブジェクトを返すメソッドを定義する。
enum LunchSet {
GOHAN("ご飯セット", 0),
SABA("サバ味噌定食", 1),
TORI("トリ唐揚定食", 2),
NIRA("ニラ炒め定食", 4),
GOHAN_DAI("ご飯セット大盛り", 8),
SABA_DAI("サバ味噌定食大盛り", 9),
TORI_DAI("トリ唐揚定食大盛り", 10),
NIRA_DAI("ニラ炒め定食大盛り", 12);
private final String name;
private final int flag;
private LunchSet(String name, int flag) {
this.name = name;
this.flag = flag;
}
public String getName() {
return name;
}
public int getFlag() {
return flag;
}
public static LunchSet getByFlag(int flag) {
return Arrays.stream(values())
.filter(s -> s.getFlag() == flag)
.findFirst()
.orElse(LunchSet.GOHAN);
}
}
こんなふうにフラグからビットの論理和を求めて取得できる。
int flag = 0;
if (useSaba) { flag += 1; }
if (useTori) { flag += 2; }
if (useNira) { flag += 4; }
if (isOomori) { flag += 8; }
LunchSet lunchSet = LunchSet.getByFlag(flag);
でもビット演算はちょっとわかりづらい。
方法2 EnumSet
Effective Javaで有名なビット演算の置き換え。
enum Menu {
SABA,
TORI,
NIRA,
OOMORI;
}
enum LunchSet {
GOHAN("ご飯セット", EnumSet.noneOf(Menu.class)),
SABA("サバ味噌定食", EnumSet.of(Menu.SABA)),
TORI("トリ唐揚定食", EnumSet.of(Menu.TORI)),
NIRA("ニラ炒め定食", EnumSet.of(Menu.NIRA)),
GOHAN_DAI("ご飯セット大盛り", EnumSet.of(Menu.OOMORI)),
SABA_DAI("サバ味噌定食大盛り", EnumSet.of(Menu.SABA, Menu.OOMORI)),
TORI_DAI("トリ唐揚定食大盛り", EnumSet.of(Menu.TORI, Menu.OOMORI)),
NIRA_DAI("ニラ炒め定食大盛り", EnumSet.of(Menu.NIRA, Menu.OOMORI));
private final String name;
private final EnumSet<Menu> flag;
private LunchSet(String name, EnumSet<Menu> flag) {
this.name = name;
this.flag = flag;
}
public String getName() {
return name;
}
public EnumSet<Menu> getFlag() {
return flag;
}
public static LunchSet getByFlag(EnumSet<Menu> flag) {
return Arrays.stream(values())
.filter(s -> s.getFlag().equals(flag))
.findFirst()
.orElse(LunchSet.GOHAN);
}
}
こんなふうにEnumSetのフラグから取得できる。
EnumSet<Menu> flag = EnumSet.noneOf(Menu.class);
if (useSaba) { flag.add(Menu.SABA); }
if (useTori) { flag.add(Menu.TORI); }
if (useNira) { flag.add(Menu.NIRA); }
if (isOomori) { flag.add(Menu.OOMORI); }
LunchSet lunchSet = LunchSet.getByFlag(flag);
コード量が増えるのが難点だけど、ビット演算よりは何をしているのかわかるようになり、Enumからフラグのセットを求める逆の操作もやりやすい。