Правильный шаблон проектирования для передачи флагов объекту
В Си я делал такие вещи
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. Затем этот служебный класс будет передан объекту, который должен использовать флаги.