web-dev-qa-db-fra.com

Comment activer l'héritage enum

J'écris une bibliothèque, qui a un ensemble prédéfini de valeurs pour un enum. Disons, mon enum ressemble à celui ci-dessous.

public enum EnumClass {
    FIRST("first"),
    SECOND("second"),
    THIRD("third");

    private String httpMethodType;

}

Maintenant, le client qui utilise cette bibliothèque peut avoir besoin d'ajouter quelques valeurs supplémentaires. Disons que le client doit ajouter CUSTOM_FIRST et CUSTOM_SECOND. Cela n'écrase pas les valeurs existantes, mais donne l'énumération à 5 valeurs.

Après cela, je devrais pouvoir utiliser quelque chose comme <? extends EnumClass> avoir 5 possibilités constantes.

Quelle serait la meilleure approche pour y parvenir?

36
Kiran A B

Vous ne pouvez pas avoir un enum étendre un autre enum, et vous ne pouvez pas "ajouter" de valeurs à un enum existant par héritage.

Cependant, enums peut implémenter interfaces.

Ce que je ferais, c’est que le enum original mette en œuvre un marqueur interface (c’est-à-dire, aucune déclaration de méthode), votre client pourrait alors créer son propre enum en implémentant le même interface.

Ensuite, vos valeurs enum seront désignées par leur commun interface.

Pour renforcer les exigences, vous pouvez demander à votre interface de déclarer les méthodes pertinentes, par exemple. dans votre cas, quelque chose dans les lignes de public String getHTTPMethodType();.

Cela forcerait l'implémentation de enums à fournir une implémentation pour cette méthode.

Ce paramètre, associé à une documentation appropriée sur l'API, devrait permettre d'ajouter des fonctionnalités de manière relativement contrôlée.

Exemple autonome (ne vous occupez pas des noms paresseux ici)

package test;

import Java.util.ArrayList;
import Java.util.List;

public class Main {

    public static void main(String[] args) {
        List<HTTPMethodConvertible> blah = new ArrayList<>();
        blah.add(LibraryEnum.FIRST);
        blah.add(ClientEnum.BLABLABLA);
        for (HTTPMethodConvertible element: blah) {
            System.out.println(element.getHTTPMethodType());
        }
    }

    static interface HTTPMethodConvertible {
        public String getHTTPMethodType();
    }
    static enum LibraryEnum implements HTTPMethodConvertible {
        FIRST("first"),
        SECOND("second"),
        THIRD("third");
        String httpMethodType;
        LibraryEnum(String s) {
            httpMethodType = s;
        }
        public String getHTTPMethodType() {
            return httpMethodType;
        }
    }
    static enum ClientEnum implements HTTPMethodConvertible {
        FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
        String httpMethodType;
        ClientEnum(String s){
            httpMethodType = s;
        }
        public String getHTTPMethodType() {
            return httpMethodType;
        }
    }
}

sortie

first
POST
43
Mena

Les énumérations ne sont pas extensibles. Pour résoudre votre problème simplement

  • tourner l'énum dans une classe
  • créer des constantes pour les types prédéfinis
  • si vous voulez un remplacement pour Enum.valueOf: suit toutes les occurrences de la classe dans une carte statique

Par exemple:

public class MyType {
    private static final HashMap<String,MyType> map = new HashMap<>();
    private String name;
    private String httpMethodType;

    // replacement for Enum.valueOf
    public static MyType valueOf(String name) {
         return map.get(name);
    }

    public MyType(String  name, String httpMethodType) {
         this.name = name;
         this.httpMethodType = httpMethodType;
         map.put(name, this);
    }

    // accessors
    public String name() { return name; }
    public String httpMethodType() { return httpMethodType; }

    // predefined constants
    public static final MyType FIRST = new MyType("FIRST", "first");
    public static final MyType SECOND = new MyType("SECOND", "second");
    ...
}
7
wero

Pensez à Enum comme une classe finale avec des instances finales statiques. Bien sûr, vous ne pouvez pas étendre la classe finale, mais vous pouvez utiliser une classe non finale avec des instances finales statiques dans votre bibliothèque. Vous pouvez voir un exemple de ce type de définition dans JDK. La classe Java.util.logging.Level peut être étendue avec une classe contenant un ensemble supplémentaire de niveaux de journalisation.

Si vous acceptez ce mode d'implémentation, votre exemple de code de bibliothèque peut ressembler à:

public class EnumClass {
    public static final FIRST = new EnumClass("first");
    public static final SECOND = new EnumClass("second");
    public static final THIRD = new EnumClass("third");

    private String httpMethodType;

    protected EnumClass(String name){
        this.httpMethodType = name;
    }
}

L'application client peut étendre la liste des membres statiques avec héritage:

public final class ClientEnum extends EnumClass{
    public static final CUSTOM_FIRST = new ClientEnum("custom_first");
    public static final CUSTOM_SECOND = new ClientEnum("custom_second");

    private ClientEnum(String name){
        super(name);    
    }
}

Je pense que cette solution est proche de ce que vous avez demandé, car toutes les instances statiques sont visibles depuis la classe client et qu'elles satisferont toutes à votre caractère générique générique.

1
Fertonder Brate

Nous avons corrigé le problème d'héritage enum de cette façon, espérons que cela aide

Notre application a peu de classes et chacune a peu de vues enfants (vues imbriquées), afin de pouvoir naviguer entre les vues enfants et enregistrer la vue currentChildview, nous les avons enregistrées en tant qu'énum dans chaque classe. mais nous avons dû copier coller, quelques fonctionnalités communes comme next, previous et etc dans chaque énumération. Pour éviter que nous ayons besoin d'un BaseEnum, nous avons utilisé l'interface comme base de base:

public interface IBaseEnum {
    IBaseEnum[] getList();
    int getIndex();

    class Utils{
        public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
            int index = enumItem.getIndex();
            IBaseEnum[] list = enumItem.getList();
            if (index + 1 < list.length) {
                return list[index + 1];
            } else if(isCycling)
                return list[0];
            else
                return null;
        }

        public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
            int index = enumItem.getIndex();
            IBaseEnum[] list = enumItem.getList();

            IBaseEnum previous;
            if (index - 1 >= 0) {
                previous = list[index - 1];
            }
            else {
                if (isCycling)
                    previous = list[list.length - 1];
                else
                    previous = null;
            }
            return previous;
        }
    }
}

et voici comment nous l'avons utilisé

enum ColorEnum implements IBaseEnum {
    RED,
    YELLOW,
    BLUE;
    @Override
    public IBaseEnum[] getList() {
        return values();
    }

    @Override
    public int getIndex() {
        return ordinal();
    }

    public ColorEnum getNext(){
    return (ColorEnum) new Utils().next(this,false);
    }

    public ColorEnum getPrevious(){
        return (ColorEnum) new Utils().previous(this,false);
    }
}

vous pouvez aussi ajouter getNext/getPrevious à l'interface

0
Annie