Subclassing an enum

2020-08-09 09:08发布

is there a simple way to subclass a Java enum?

I ask this because I have like 10 of them that implement the same interface but they also have the same implementation for some methods so I would like to reuse the code by placing all the same implementations in middle object that extends Enum and it is also the superclass of all the others I need.

Maybe it is not so straightforward as I think?

Thank in advance

7条回答
beautiful°
2楼-- · 2020-08-09 09:57

Whilst there have been proposals for abstract enums in Java, the benefits are considered far too low to outweigh the costs. You'll have to stick with forwarding method calls.

查看更多
在下西门庆
3楼-- · 2020-08-09 09:58

The language does not allow you to do so, as Enums are designed for representing enumerated values efficiently, not for implementing code. Try using another pattern like a static helper (utility) class.

查看更多
够拽才男人
4楼-- · 2020-08-09 10:07

You can't do it, since the language does not allow you. And for a good logical reason: subclassing an enum would only make sense if you could remove some enum values from the subclass, not add new ones. Otherwise you would break the Liskov Substitution Principle.

This in brief states that every instance of a subclass should be acceptable whenever an instance of a superclass is expected. If you add a new enum member in an enum subclass, that clearly can't be accepted by someone knowing only the super enum.

For more details and possible alternatives, see this earlier answer of mine.

In your concrete case, @Jason's suggestion may offer a good solution (+1 for him :-)

Update to @OrangeDog's comment

Good point, I was a bit sloppy above :-) Implementation-wise you are right. However, from the logical point of view an enum type is fully described by the set of its valid values. And generally, a proper subclass is a specialization of its superclass. In other words, the set of valid subclass instances is (should be) always a subset of the superclass instance set. (Every dog is an animal, but not every animal is a dog.)

查看更多
做个烂人
5楼-- · 2020-08-09 10:07

With Java 8 you can put the shared implementation in the interface using default methods.

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();
    }
}

If access to methods implemented by the Enum class is required, add the signature to the interface:

public interface Greeter {

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

    /**
     * @see Enum#name()
     */
    public String name(); // implemented by Enum
}
查看更多
▲ chillily
6楼-- · 2020-08-09 10:10

@Jason S has offered a good reply, but the static method make you lose the OOP's potentialities.

What about delegation? I mean:

  1. Define a common interface "I_A" where you defines all getters/setters and all other methods.

  2. Define a "struct-like" class "S_C" : it implements only the getters and setters, other methods are empty because are useless.

  3. To make your enumerations shorter (in terms of lines of code), define a second interface "I_A_Delegating" that extends the first ones, has an additional getter/setter of type "I_A" (it's our delegator) and, thanks to Java's default methods, define the getter/setter as calling the delegator's getter/setter.

  4. All of your enumerations implements "I_A_Delegating" and has a local instance of "S_C"

Code example:

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*/
        }
    }
}
查看更多
贼婆χ
7楼-- · 2020-08-09 10:14

I ask this because I have like 10 of them that implement the same interface but they also have the same implementation for some methods so I would like to reuse the code by placing all the same implementations in middle object that extends Enum and it is also the superclass of all the others I need.

How about using a static helper class?

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);
    }
};
查看更多
登录 后发表回答