6

Можно ли наследовать перечисления для добавления новых элементов?

26

Я хочу взять уже существующий enum и добавить в него новые элементы следующим образом:

enum A {a, b, c}

enum B extends A {d}

/*B = {a, b, c, d}*/

Возможно ли это сделать в Java?

5 ответ(ов)

5

Нет, вы не можете сделать это в Java. Кроме всего прочего, d тогда, по всей видимости, будет экземпляром класса A (с учетом обычного понимания "наследования"), но пользователи, знающие только о A, не будут об этом знать, что сводит на нет саму суть enum как хорошо известного множества значений.

Если вы расскажете подробнее о том, как вы планируете использовать это, мы могли бы предложить альтернативные решения.

3

Enums представляют собой полное перечисление возможных значений. Поэтому (возможно, не столь полезный) ответ - нет.

В качестве реальной задачи можно рассмотреть дни недели: будние дни, выходные и, соответственно, дни недели. Мы могли бы определить все дни в рамках дней недели, но тогда не сможем представить свойства, уникальные для будних и выходных дней.

Что мы можем сделать, так это создать три типа enum с отображением между будними/выходными днями и днями недели.

public enum Weekday {
    MON, TUE, WED, THU, FRI;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay {
    SAT, SUN;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
    MON, TUE, WED, THU, FRI, SAT, SUN;
}

Альтернативный подход - создать расширяемый интерфейс для дней недели:

interface Day {
    ...
}
public enum Weekday implements Day {
    MON, TUE, WED, THU, FRI;
}
public enum WeekendDay implements Day {
    SAT, SUN;
}

Или мы могли бы совместить оба подхода:

interface Day {
    ...
}
public enum Weekday implements Day {
    MON, TUE, WED, THU, FRI;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay implements Day {
    SAT, SUN;
    public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
    MON, TUE, WED, THU, FRI, SAT, SUN;
    public Day toDay() { ... }
}

Таким образом, благодаря этим подходам мы можем эффективно моделировать дни недели, учитывая уникальные свойства будних и выходных дней, избегая при этом ограничений, связанных с использованием одного только enum.

0

Внутри реализации ваше ENUM - это просто обычный класс, сгенерированный компилятором. Этот сгенерированный класс наследует java.lang.Enum. Техническая причина, по которой вы не можете расширять сгенерированный класс, заключается в том, что он объявлен как final. Концептуальные причины его финальности обсуждаются в этой теме. Однако я добавлю некоторые механизмы в обсуждение.

Вот тестовый enum:

public enum TEST {  
    ONE, TWO, THREE;
}

Сгенерированный код от javap:

public final class TEST extends java.lang.Enum<TEST> {
  public static final TEST ONE;
  public static final TEST TWO;
  public static final TEST THREE;
  static {};
  public static TEST[] values();
  public static TEST valueOf(java.lang.String);
}

Теоретически, вы могли бы самостоятельно реализовать этот класс и убрать final. Но компилятор не позволяет вам напрямую расширять java.lang.Enum. Вы также можете решить не наследовать от java.lang.Enum, но тогда ваш класс и его производные классы не будут являться экземплярами java.lang.Enum, что, возможно, для вас не будет иметь значения!

0

Привет! Ваш вопрос касается использования перечислений (enum) в Java и их группировки для обработки событий, что действительно может облегчить работу с разными состояниями и уменьшить количество кода в условных операторах.

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

Ваша основная идея заключается в том, чтобы создать несколько групп состояний (в данном случае, State_StatusGroup), каждая из которых содержит члены, представляющие операции статуса. Именно использование интерфейса StatusGroupInterface позволяет достичь некоторой степени многократного наследования для перечислений.

Преимущества такого подхода:

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

  2. Многократное наследование: Ваши перечисления могут группироваться по различным аспектам. Например, события банкомата можно классифицировать по статусу, типу операции и другим критериям.

  3. Компактный код: Вместо множества условных операторов switch, вы можете использовать метод is для проверки статуса события. Это не только уменьшает количество кода, но и делает его более понятным.

Пример использования

Ваш пример с арганизацией обработки событий выглядит очень наглядно. Вы определяете, что делать при определенных событиях, таких как START, STEP, и FINISH, при помощи простых условий:

if(myEvent.is(State_StatusGroup.START)) {
    makeNewOperationObject();
} else if(myEnum.is(State_StatusGroup.STEP)) {
    makeSomeSeriousChanges();
} else if(myEnum.is(State_StatusGroup.FINISH)) {
    closeTransactionOrSomething();
}

Надстройки

Вы также упомянули о более сложном примере с AtmEventType, где перечисления связываются с несколькими группами, что позволяет продвинутым пользователям обращаться с различными аспектами события, такими как статус, авторизация и изменения состояния счета. Это действительно мощный способ структурирования вашего кода.

public enum AtmEventType {
    USER_DEPOSIT(Status_EventsGroup.WITH_STATUS, ...),
    // другие события
}

Заключение

Ваш подход предоставляет отличный способ организации логики обработки событий с использованием перечислений в Java. Это не только упрощает код, делая его более удобочитаемым, но также вводит дополнительные структурные элементы, которые могут быть полезны для сложных бизнес-логик. Продолжайте экспериментировать с такими концепциями, и вы увидите, как они могут значительно упростить разработку!

0

В данном ответе я хотел бы показать, как можно расширить перечисление (enum) с помощью другого перечисления, используя достаточно простой подход.

Предположим, у вас есть перечисление с общими константами:

public interface ICommonInterface {
    String getName();
}

public enum CommonEnum implements ICommonInterface {
    P_EDITABLE("editable"),
    P_ACTIVE("active"),
    P_ID("id");

    private final String name;

    CommonEnum(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }
}

Теперь вы можете попробовать создать новое перечисление, которое будет "расширять" предыдущее, вот так:

public enum SubEnum implements ICommonInterface {
    P_EDITABLE(CommonEnum.P_EDITABLE),
    P_ACTIVE(CommonEnum.P_ACTIVE),
    P_ID(CommonEnum.P_ID),
    P_NEW_CONSTANT("new_constant");

    private final String name;

    SubEnum(CommonEnum commonEnum) {
        this.name = commonEnum.getName();
    }

    SubEnum(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }
}

Однако, есть важный нюанс: всякий раз, когда вам нужно будет добавить новую константу в SubEnum, вам придется вручную изменять файлы SubEnum. Это стоит учитывать при проектировании архитектуры вашего кода, поскольку может увеличивать объем работы при добавлении новых значений.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь