Правильный шаблон проектирования для передачи флагов объекту

В Си я делал такие вещи

enum { USE_COKE = 1,
        USE_PEPSI = 2,
        USE_JUICE = 4,
        USE_WATER = 8 };

 int makeDrink(int flags);

 //...

 int rcode = makeDrink(USE_COKE | USE_JUICE | USE_WATER);

Я знаю, что это довольно стандартно, он также используется в iostream например. Мне интересно, как перевести этот шаблон проектирования в Java или ООП? Я почти уверен, что полиморфизм - это не тот способ, с помощью которого мой код должен иметь if(flag_is_set) блок, чем переписать большую часть рутины. Есть ли утилита Flags класс, или предпочтительный способ сделать это с помощью объекта конфигурации, или enumили куча целых и т. д.

4 ответа

Решение

У Java есть перечисления. Вот учебник.

Я бы использовал их над целыми числами и т. Д. Это безопасное для типов решение, и поскольку перечисления являются объектами, вы можете прикрепить поведение и избежать switch заявления.

Вы можете объединить их (как указано выше), используя EnumSet. Из документа:

Специализированная реализация Set для использования с типами enum... Это представление чрезвычайно компактно и эффективно. Пространственно-временные характеристики этого класса должны быть достаточно хорошими, чтобы его можно было использовать в качестве высококачественной, безопасной для типов альтернативы традиционным "битовым флагам" на основе int.

Ответ Брайана Агнью правильный. Java обладает мощным, гибким и совершенно удобным Enum объект. (Не путать с устаревшим Enumeration интерфейс.)

Пример кода

Вот пример кода, основанного на вопросе.

public enum Liquid {
    COKE, PEPSI, JUICE, WATER
}

Метод, принимающий EnumSet этого типа enum.

public Drink makeDrink ( EnumSet<Liquid> ingredients ) {
    System.out.println ( "ingredients: " + ingredients );
    if ( ingredients.contains ( Liquid.JUICE ) ) {
        // Treat as a Collection. 
        // `EnumSet` is just another `Set` implementation, though a very fast one.
    }
    for ( Liquid ingredient : ingredients ) {
        // Access each item in the collection, each Liquid object in the EnumSet.
    }
}

Код, вызывающий этот метод, создающий и передающий необходимый EnumSet,

EnumSet ingredients = EnumSet.of ( Liquid.COKE , Liquid.JUICE , Liquid.WATER );
Drink drink = this.makeDrink ( ingredients );

Когда беги.

ингредиенты: [КОКС, СОК, ВОДА]

Имейте в виду, что это реальные объекты, типобезопасные, с принудительной компиляцией, статически определенные и самодокументируемые. Не путайте их с простыми строками.

У вас также есть Java EnumMap, так что вы можете получить значение из EnumMap из всех USE_XXX необходимо выпить перед тем, как передать их на ваш метод

Есть несколько вариантов реализации этого.

  • Мне лично нравится стиль битовых манипуляций в стиле C, просто создание перечисления или набора окончательных статик.
  • Другой вариант в Java - использовать объект java.util.BitSet.
  • Вероятно, самым чистым из истинного представления ООП будет реализация служебного класса с логическими значениями getter/setters. Затем этот служебный класс будет передан объекту, который должен использовать флаги.
Другие вопросы по тегам