Лучшая практика использования флагов в методе Java
какова наилучшая практика указания флагов в методе Java?
Я видел SWT, использующий int как bitfields, например:
(пример частично из " эффективной Java, 2-е изд."страница 159):
public class Text {
  public static final int STYLE_BOLD = 1 << 0; // 1
  public static final int STYLE_ITALIC = 1 << 1; // 2
  void printText(String text, int flags) {
  }
}
и ваш клиент выглядит так:
printText("hello", Text.STYLE_BOLD | Text.STYLE_ITALIC);
..но это не рекомендуется, поскольку вы можете смешивать флаги (значения int) из разных классов вместе без каких-либо проверок компилятора.
в той же книге ("эффективная Java"), я вижу использование EnumSet, но затем ваш пользовательский вызов становится:
printText("hello", EnumSet.of(Style.Bold, Style.ITALIC));
Я нахожу это немного многословным, и я предпочитаю элегантность SWT.
есть ли другая альтернатива или это в основном два вкуса, которые вы должны выбрать?
5 ответов
думаю, вы попали в стену. Я не вижу другого выхода. Java-это многословный это факт. В таких ситуациях я обычно добавляю локальную переменную, чтобы сделать код более читаемым. Ты можешь это сделать,
EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.ITALIC);
printText("hello", styles);
Если вы хотите флаги битового стиля, Java обертывает их в BitSet.  Это было вокруг в течение многих лет, но мало кто беспокоится использовать его (предпочитая встраивание бит стиля C в ints).
api для BitSet можно найти здесь.
в сочетании с несколькими хорошо выбранными статическими интами, он делает довольно хорошо, пока вы не начнете проверять и устанавливать несколько битов за один проход.
я советую вам пойти с EnumSet подход. 
EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.Italic);
этот подход обеспечивает лучшую безопасность типов, и Style быть перечислением будет иметь полномасштабные возможности OO.
поздний ответ для тех, кто сталкивается с этим. Вот один из способов сделать это, чтобы уменьшить память и иметь хорошее перечисление, как api:
public static class MyFlag {
    public static final MyFlag A = new MyFlag(1<<0);
    public static final MyFlag B = new MyFlag(1<<1);
    public static final MyFlag C = new MyFlag(1<<2);
    public static final MyFlag ALL = A.and(B).and(C);
    private final int flag;
    private MyFlag(int flag){
        this.flag = flag;
    }
    public MyFlag and(MyFlag limit){
        return new MyFlag(flag & limit.flag);
    }
    public MyFlag not(MyFlag limit){
        return new MyFlag(flag | ~limit.flag);
    }
    public boolean isSet(MyFlag limit){
        if(limit ==null){
            return false;
        }
        return (this.flag & limit.flag) != 0;
    }
}
способ:
public void doFoo(MyFlag flag){
   if(MyFlag.A.isSet(flag)){
   ....
   }
   if(MyFlag.C.isSet(flag)){
   ....
   }
}
звоните:
x.doFoo(MyFlag.A.and(MyFlag.C));
если у вас есть только ограниченное количество методов, которые будут принимать набор стилей (например,printText в вашем примере), вы можете настроить свою подпись, чтобы принимать переменное число параметров типа:
void printText(String text, Style... flags) {
  EnumSet<Style> style = logicalOr(flags); // see comment below
  ...
 }
и тогда ваши вызовы очень близки к нетипизированному (int) маршруту флага:
printText("hello", Style.BOLD, Style.ITALIC);
к сожалению, нет EnumSet.of(E... ) завода,EnumSet.of(E first, E... more), так что вам понадобится общий logicalOr метод для разделения массива на первые + rest куски.  оставил в качестве упражнения для читатель =).