Подклассы перечисления - PullRequest
       11

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

15 голосов
/ 05 января 2011

Есть ли простой способ создать подкласс Java enum?

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

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

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

Ответы [ 7 ]

18 голосов
/ 05 января 2011

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

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

Для получения более подробной информации и возможных альтернатив см. мой предыдущий ответ .

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

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

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

11 голосов
/ 05 января 2011

Я спрашиваю об этом, потому что у меня около 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);
    }
};
4 голосов
/ 15 августа 2017

В 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
}
2 голосов
/ 20 февраля 2012

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

2 голосов
/ 05 января 2011

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

0 голосов
/ 10 декабря 2017

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

А как насчет делегирования?Я имею в виду:

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

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

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

  4. Все ваши перечисления реализуют "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*/
        }
    }
}
0 голосов
/ 05 января 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...