← Назад к вопросам

Что такое Int Enum pattern?

2.3 Middle🔥 151 комментариев
#SOLID и паттерны проектирования#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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 PatternEnum
ТипобезопасностьНет (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 поддержку.