Vraag Kan ik een abstracte enum maken in Java?


Hieronder staat een geldige opsommingsverklaring.

public enum SomeEnumClass {

    ONE(1), TWO(2), THREE(3);

    private int someInt;

    public SomeEnumClass(int someInt) {
        this.someInt = someInt;
    }
}

Maar kan ik een abstracte klasse overschrijven met een enum-type?

SomeEnumClass.java

public abstract enum SomeEnumClass {

    private int someInt;

    public SomeEnumClass(int someInt) {
        this.someInt = someInt;
    }
}

OverridingEnumClass.java

public enum OverridingEnumClass extends SomeEnumClass {

    ONE(1), TWO(2), THREE(3);

}

Zo nee, waarom niet? En wat is een goed alternatief?


28
2017-11-30 10:22


oorsprong


antwoorden:


Nee, dat kan niet; enum-typen breiden zich uit Enumen ze zijn impliciet final. Enums kunnen interfaces implementeren, of u kunt de relevante methoden direct op de betreffende klasse in kwestie declareren.

(Ik zie wel het basisidee van wat je wilt, wat een mix is, misschien zijn de Java 8-interfaces in dit opzicht een beetje nuttiger.)


30
2017-11-30 10:25



Als u echt een enum wilt uitbreiden, kunt u het pre-Java 1.5 Typesafe Enum-patroon gebruiken (zie de onderkant van http://www.javacamp.org/designPattern/enum.html ) die feitelijk een klasse gebruikt, geen enum. U verliest de mogelijkheid om de EnumSet te gebruiken met uw "enum" en u verliest enkele automatisch gegenereerde methoden zoals items (), maar u krijgt de mogelijkheid om methoden te overschrijven.

Een voorbeeld:

// Typesafe enum pattern
public static abstract class Operator {
    public static final Operator ADD = new Operator("+") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam + secondParam;
        }
    };
    public static final Operator SUB = new Operator("-") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam - secondParam;
        }
    };
    public static final Operator MUL = new Operator("*") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam * secondParam;
        }
    };
    public static final Operator DIV = new Operator("/") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam / secondParam;
        }
    };

    private static final Operator[] _ALL_VALUES = {ADD, SUB, MUL, DIV};
    private static final List<Operator> ALL_VALUES = Collections.unmodifiableList(Arrays.asList(_ALL_VALUES));

    private final String operation;

    private Operator(String c) {
        operation = c;
    }

    // Factory method pattern
    public static Operator fromToken(String operation) {
        for (Operator o : Operator.items())
            if (o.operation.equals(operation))
                return o;
        return null;
    }

    public Iterable<Operator> items() {
        return ALL_VALUES;
    }

    public abstract Double apply(Double firstParam, Double secondParam); 

}

4
2017-08-09 07:12



In Java kun je Enum niet uitbreiden of een abstract enum maken of zelfs Enum genereren. Als je een polymorf extensie punt over je enum wilt hebben, kun je een dergelijk patroon toepassen.

Laten we uw opsomming zeggen

public enum SomeEnumClass {
    ONE, TWO, THREE;
}

En u wilt gedrag vertonen dat is gekoppeld aan elke waarde. Maar u wilt niet elk van hen hardcoderen, maar liever de mogelijkheid hebben om een ​​ander te leveren. Dus je moet de interface declareren

public interface SomeEnumVisitor<P, R> {
     R one(P param);
     R two(P param);
     R three(P param);
}

Voeg vervolgens een abstracte methode toe om de declaratie en implementatie van deze methode voor elke waarde op te stellen

public enum SomeEnumClass {
    ONE {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.one(param);
        }
    }, TWO {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.two(param);
        }
    }, THREE {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.three(param);
        }
    };
    public abstract <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param);
}

Zodat u de bezoekersimplementatie kunt maken voor uitbreiding van uw opsommingsgedrag. In uw geval wilde u bijvoorbeeld Geheel getalwaarde associëren met elke enumwaarde.

public class IntValueVisitor implements SomeClassVisitor<Integer, Void> {
     @Override
     public Integer one(Void param){
         return 1;
     }

     @Override
     public Integer two(Void param){
         return 2;
     }

     @Override
     public Integer three(Void param){
         return 3;
     }    
}

En gebruik deze bezoeker uiteindelijk waar je hem nodig hebt

SomeClassEnum something = getAnyValue();
// this expression will return your particular int value associated with particular enum.
int intValue = something.accept(new IntValueVisitor(), null);

Uiteraard is dit patroon van toepassing als het niet gepast is om alles binnen een opsomming te laten verklaren, bijvoorbeeld als u een opsomming in de bibliotheek hebt en het gedrag van enum in de hoofdtoepassing wilt uitbreiden. Of u wilt gewoon de definitie- en implementatiedetails van het enum niet koppelen.

Om deze patroonimplementatie te vereenvoudigen er is een bibliotheek die opsomming en bezoeker kan genereren op basis van annotatie zodat alles wat je moet declareren in je code is

@AutoEnum(value = {"one", "two", "three"}, name = "SomeEnumClass")
public interface SomeEnumMarker {}

De tool zal rust voor je doen.


3
2018-02-06 09:59