Лучшая практика использования флагов в методе Java - PullRequest
8 голосов
/ 20 мая 2011

Как лучше всего указывать флаги в методе Java?

Я видел SWT, использующий int в качестве битовых полей, например:

(пример частично из "Effective Java, 2nd Ed."страница 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 ]

7 голосов
/ 20 мая 2011

Думаю, вы ударились о стену.Я не вижу другого варианта.Ява многословна, это факт.В подобных ситуациях я обычно добавляю локальную переменную, чтобы сделать код более читабельным.Вы можете сделать это,

EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.ITALIC);
printText("hello", styles);
2 голосов
/ 20 мая 2011

Я советую вам придерживаться подхода EnumSet.

EnumSet<Style> styles = EnumSet.of(Style.Bold, Style.Italic);

Этот подход обеспечивает лучшую безопасность типов, и Style, будучи перечислением, будет иметь полноценные возможности OO.

2 голосов
/ 20 мая 2011

Если вам нужны флаги в битовом стиле, Java заключает их в BitSet. Он существует уже целую вечность, но мало кто потрудился использовать его (предпочитая встраивать обработку битов в стиле C в целые).

API для BitSet можно найти здесь .

В сочетании с несколькими хорошо подобранными статическими целочисленными значениями он работает довольно хорошо, пока вы не начнете проверять и устанавливать несколько битов за один проход.

1 голос
/ 20 апреля 2015

Поздний ответ для всех, кто сталкивался с этим. Вот один из способов сделать это, чтобы уменьшить память и получить хороший список, например, 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));
0 голосов
/ 18 октября 2017

Если у вас есть только ограниченное количество методов, которые будут использовать набор стилей (например, 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 метод для разделения вашего массива на первый + остальные куски. Предоставлено читателю как упражнение =) .

...