Что такое Int Enum pattern?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Int Enum Pattern в Java
Int Enum Pattern — это паттерн, когда вместо типобезопасного enum используются целые числа (int) для представления состояний или типов. Это антипаттерн в современной Java и его следует избегать, но он часто встречается в legacy коде.
Проблема: Int constants вместо Enum
// ❌ Старый способ (Int Enum Pattern) — НЕ РЕКОМЕНДУЕТСЯ
public class Status {
public static final int PENDING = 0;
public static final int APPROVED = 1;
public static final int REJECTED = 2;
public static final int CANCELLED = 3;
}
public class Order {
private int status; // Какое значение здесь валидно?
}
// Использование:
Order order = new Order();
order.setStatus(Status.PENDING); // Правильно
order.setStatus(99); // ❌ Ошибка, но компилятор не поймёт
order.setStatus(-1); // ❌ Ошибка, но компилятор не поймёт
order.setStatus("Pending"); // ❌ Не скомпилируется (это хорошо)
Причины, почему это проблема
1. Отсутствие типобезопасности
public void processOrder(int status) {
if (status == 1) { // Что означает 1? APPROVED? PENDING?
// ...
}
}
processOrder(999); // Скомпилируется, но будет ошибка в runtime
2. Плохая читаемость кода
// Что здесь происходит?
if (order.getStatus() == 1) {
//...
}
// Нужно запомнить все числа
if (order.getStatus() == Status.APPROVED) { // Намного понятнее
// ...
}
3. Сложность рефакторинга
// Если нужно добавить новый статус, где все изменения?
public class Status {
public static final int PENDING = 0;
public static final int APPROVED = 1;
// public static final int ON_HOLD = 4; // Добавили
public static final int REJECTED = 2;
}
// А где ещё используется 1, 2, 3? Сложно найти все места
4. Проблемы с сохранением в БД
// Если в коде используется 0, 1, 2, а в БД сохранены 1, 2, 3?
// Это вызовет путаницу и ошибки
Правильный способ: типобезопасный Enum
// ✅ Современный способ (Java 5+) — РЕКОМЕНДУЕТСЯ
public enum Status {
PENDING(0),
APPROVED(1),
REJECTED(2),
CANCELLED(3);
private final int value;
Status(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static Status fromValue(int value) {
for (Status status : values()) {
if (status.value == value) {
return status;
}
}
throw new IllegalArgumentException("Unknown status: " + value);
}
}
public class Order {
private Status status; // Типобезопасно!
}
// Использование:
Order order = new Order();
order.setStatus(Status.PENDING); // ✅ Правильно
order.setStatus(99); // ❌ Не скомпилируется
if (order.getStatus() == Status.APPROVED) { // Очень понятно
// ...
}
Преимущества типобезопасного Enum
| Аспект | Int Pattern | Enum |
|---|---|---|
| Типобезопасность | Нет (int может быть любой) | Да |
| Читаемость | Плохая (0, 1, 2?) | Отличная (PENDING, APPROVED) |
| IDE автодополнение | Нет | Да |
| Рефакторинг | Сложно | Легко |
| Нарушение инкапсуляции | Да | Нет |
Миграция с Int Enum Pattern на Enum
Если в legacy коде используется Int Enum Pattern:
// Старый код
public class Status {
public static final int PENDING = 0;
public static final int APPROVED = 1;
}
// Новый код
public enum OrderStatus {
PENDING(0),
APPROVED(1);
private final int value;
OrderStatus(int value) { this.value = value; }
public int getValue() { return value; }
public static OrderStatus fromValue(int value) {
for (OrderStatus s : values()) {
if (s.value == value) return s;
}
throw new IllegalArgumentException("Unknown status: " + value);
}
}
// Адаптация для совместимости
public class StatusAdapter {
public static int toInt(OrderStatus status) {
return status.getValue();
}
public static OrderStatus fromInt(int value) {
return OrderStatus.fromValue(value);
}
}
Современные альтернативы для базирования на целых числах
Если нужно хранить числовые коды в БД:
// Вариант 1: Enum с @Convert (JPA)
@Entity
public class Order {
@Convert(converter = OrderStatusConverter.class)
private OrderStatus status;
}
@Converter(autoApply = true)
public class OrderStatusConverter implements AttributeConverter<OrderStatus, Integer> {
@Override
public Integer convertToDatabaseColumn(OrderStatus status) {
return status == null ? null : status.getValue();
}
@Override
public OrderStatus convertToEntityAttribute(Integer value) {
return value == null ? null : OrderStatus.fromValue(value);
}
}
// Вариант 2: Spring Data с Custom Converter
@Configuration
public class DataConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToOrderStatusConverter());
}
}
Пример использования в Spring
@RestController
public class OrderController {
@PostMapping("/orders")
public Order createOrder(@RequestParam OrderStatus status) {
// status автоматически преобразуется из String "PENDING" в enum
return orderService.create(status);
}
}
@Service
public class OrderService {
public void updateOrderStatus(Long orderId, OrderStatus newStatus) {
Order order = orderRepository.findById(orderId).orElseThrow();
order.setStatus(newStatus);
orderRepository.save(order);
}
}
Int Enum Pattern в Android (исторический контекст)
Int Enum Pattern часто встречается в Android, где на момент создания некоторых API enum потреблял слишком много памяти:
// Android View.OnClickListener.OnClick использует это
public static final int VISIBLE = 0;
public static final int INVISIBLE = 4;
public static final int GONE = 8;
Но даже в Android сейчас рекомендуется использовать @IntDef для типобезопасности:
@IntDef({View.VISIBLE, View.INVISIBLE, View.GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface ViewVisibility {}
public void setVisibility(@ViewVisibility int visibility) {
// Только значения из аннотации допускаются
}
Итого
Int Enum Pattern — это антипаттерн, в котором вместо type-safe enum используются целые числа. Проблемы:
- Отсутствие типобезопасности
- Плохая читаемость
- Сложность рефакторинга
- Возможность ошибок в runtime
Решение: используй Java enum вместо int констант. Это обеспечивает типобезопасность, лучшую читаемость и IDE поддержку.