Подклассирование перечисления

существует простой способ подкласса Java enum?

Я спрашиваю об этом, потому что у меня есть 10 из них, которые реализуют один и тот же интерфейс, но они также имеют одну и ту же реализацию для некоторых методов, поэтому я хотел бы повторно использовать код, помещая все те же реализации в средний объект, который расширяет enum и это также суперкласс всех остальных, в которых я нуждаюсь.

Может, это не так просто, как я думаю?

Спасибо заранее

Ответы

Ответ 1

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

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

Более подробную информацию и возможные альтернативы см. этот более ранний ответ.

В вашем конкретном случае предложение @Jason может предложить хорошее решение (+1 для него: -)

Обновить до комментария @OrangeDog

Хорошая мысль, я был немного неряшливым:-) Внедрение - вы правы. Однако с логической точки зрения тип перечисления полностью описывается набором его допустимых значений. И вообще, надлежащий подкласс является специализацией его суперкласса. Другими словами, набор допустимых экземпляров подкласса (должен быть) всегда является подмножеством набора экземпляров суперкласса. (Каждая собака - животное, но не каждое животное - собака.)

Ответ 2

Я спрашиваю об этом, потому что у меня есть 10 из них, которые реализуют один и тот же интерфейс, но у них также есть одна и та же реализация для некоторых методов, поэтому я хотел бы повторно использовать код, помещая все те же реализации в средний объект, который расширяет Enum, и это также является суперклассом всех остальных, которые мне нужны.

Как использовать статический вспомогательный класс?

interface Animal
{
    public void speak();
}

class AnimalHelper
{
    public static void speakHelper(Animal animal) {
        // common methods here
    }
}

enum Dog implements Animal { SCHNAUZER, LABRADOR, ST_BERNARD, DACHSHUND;
    @Override public void speak() {
        AnimalHelper.speakHelper(this);
    }
};

enum Bird implements Animal { OWL, FINCH, DUCK, GOOSE; }
    @Override public void speak() {
        AnimalHelper.speakHelper(this);
    }
};

Ответ 3

С помощью Java 8 вы можете поместить общую реализацию в интерфейс, используя методы по умолчанию.

public class DefaultMethodOnEnumInterface {

    public interface Greeter {

        default public void greet() {
            System.out.println("Hello, world!");
        }
    }

    public enum Greeters implements Greeter {
        A,
        B;
    }

    public static void main(String[] args) {
        Greeters.A.greet();
        Greeters.B.greet();
    }
}

Если требуется доступ к методам, реализованным классом Enum, добавьте подпись в интерфейс:

public interface Greeter {

    default public void greet() {
        System.out.println("Hello, world! This is " + name());
    }

    /**
     * @see Enum#name()
     */
    public String name(); // implemented by Enum
}

Ответ 5

Попробуйте использовать Enums из пакета общих пакетов Apache, где вы можете подклассы Enums. Не знаю, поможет ли это вам.

Ответ 6

Язык не позволяет это сделать, поскольку Enums предназначены для эффективного представления нумерованных значений, а не для реализации кода. Попробуйте использовать другой шаблон, например, статический помощник (утилита).

Ответ 7

@Jason S предлагает хороший ответ, но статический метод заставляет вас потерять возможности ООП.

Как насчет делегации? Я имею в виду:

  • Определите общий интерфейс "I_A", где вы определяете все геттеры/сеттеры и все другие методы.

  • Определите "структурный" класс "S_C": он реализует только геттеры и сеттеры, другие методы пустые, потому что бесполезны.

  • Чтобы сделать ваши перечисления короче (с точки зрения строк кода), определите второй интерфейс "I_A_Delegating", который расширяет первые, имеет дополнительный getter/setter типа "I_A" (это наш делегат) и, благодаря методам Java по умолчанию, определите getter/setter как вызов получателя/сеттера делегата.

  • Все ваши перечисления реализуют "I_A_Delegating" и имеют локальный экземпляр "S_C"

Пример кода:

public class EnumFakeExtension{
     /**"I_A"*/
     public static interface CommonInterface{
           public Object getFieldOne();
           public Object getFieldTwo();

           public void setFieldOne(Object o);
           public void setFieldTwo(Object o);

           public void someMethod();
     }

     /*"S_C"*/
     public static class CommonDelegator_FieldKeeper implements CommonInterface{
         Object oOne, oTwo;
           public Object getFieldOne(){ return oOne; }
           public Object getFieldTwo(){ return oTwo; }

           public void setFieldOne(Object o){ oOne = o; }
           public void setFieldTwo(Object o){ oTwo = o; }

           public void someMethod(){ /*empty*/ }
     }


     /**"I_A_Delegating"*/
     public static interface CommonInterface_Delegating extends CommonInterface{
         public CommonInterface getDelegate();
         public void setDelegate(CommonInterface delegator);

         /**Just to simplify*/
         public default void setDefaultDelegate(CommonInterface delegator){
             setDelegate( new CommonDelegator_FieldKeeper() );
         }


         public default Object getFieldOne(){ return getDelegate().getFieldOne(); }
         public default Object getFieldTwo(){ return getDelegate().getFieldTwo(); }

         public default void setFieldOne(Object o){ getDelegate().setFieldOne(o); }
         public default void setFieldTwo(Object o){ getDelegate().setFieldTwo(o); }
     }


    /*the enums, now*/

    public static enum EnumFirst implements CommonInterface_Delegating{
        FieldA, FieldB, FieldC;

        EnumFirst (){
            setDefaultDelegate();
        }
        final CommonDelegator_FieldKeeper delegator;

        public CommonInterface getDelegate(){ return delegator; }
        public void setDelegate(CommonInterface delegator){ this.delegator=delegator; }


        public void someMethod(){
            /*do what You need*/
        }
    }


    public static enum EnumSecond implements CommonInterface_Delegating{
        FieldA, FieldB, FieldC;

        EnumSecond (){
            setDefaultDelegate();
        }
        final CommonDelegator_FieldKeeper delegator;

        public CommonInterface getDelegate(){ return delegator; }
        public void setDelegate(CommonInterface delegator){ this.delegator=delegator; }

        public void someMethod(){
            /*do what You need, again*/
        }
    }
}