19
15

More than 5 years have passed since last update.

複数のフラグからマッチするEnumオブジェクトを取得する(ビット演算とEnumSet)

Last updated at Posted at 2015-07-28

やりたいこと

こんなかんじのフラグのセットを受け取って

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からフラグのセットを求める逆の操作もやりやすい。

19
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
15