Astuce de codage - types d'intersection et énumérations java


8

Les types d'intersection permettent (en quelque sorte) de faire des énumérations qui ont une hiérarchie d'héritage. Vous ne pouvez pas hériter de l'implémentation, mais vous pouvez la déléguer à une classe d'assistance.

enum Foo1 implements Bar {} 
enum Foo2 implements Bar {} 

class HelperClass { 
    static <T extends Enum<T> & Bar> void fooBar(T the enum) {} 
} 

Ceci est utile lorsque vous avez un nombre d'énumérations différentes qui implémentent un type de motif. Par exemple, un certain nombre de paires d'énumérations qui ont une relation parent-enfant.

enum PrimaryColor {Red, Green, Blue;} 
enum PastelColor {Pink, HotPink, Rockmelon, SkyBlue, BabyBlue;} 

enum TransportMedium {Land, Sea, Air;} 
enum Vehicle {Car, Truck, BigBoat, LittleBoat, JetFighter, HotAirBaloon;} 

Vous pouvez écrire des méthodes génériques qui disent « Ok, étant donné une valeur ENUM thats un parent de quelques autres valeurs ENUM, quel pourcentage de tous les énumérations enfants possibles du type enfant ont cette valeur de parent particulier que leur parent ? ", et l'ont tous typesafe et fait sans casting. (ex: que "Mer" représente 33% de tous les véhicules possibles, et "Vert" 20% de tous les Pastels possibles).

Le code ressemble à ceci. Notez en particulier que les classes "feuilles" elles-mêmes sont plutôt soignées - mais les classes génériques ont des déclarations horriblement laides. C'est bon: vous ne les écrivez qu'une seule fois. Une fois que les classes génériques sont là, il est facile de les utiliser.

La classe auxiliaire ci-dessous a juste quelques méthodes statiques. D'autres façons d'aller inclure

  • fournissant une instance qui retourne une singleton, mais typés selon le parent /enfant
  • retourner une instance pour chaque paren/enfant, saisi de façon appropriée, et dont un en chaque ENUM mère

Avec cette deuxième option, l'objet « enfants » serait en fait à l'intérieur de l'aide, ce qui réduit la quantité de code nécessaire dans les énumérations. Ils auraient tous instancier un assistant et déléguer tout ce qui est difficile.

import java.util.EnumSet; 

import javax.swing.JComponent; 

public class zz extends JComponent { 

    public static void main(String[] args) { 
     System.out.println(PrimaryColor.Green + " " + ParentUtil.pctOf(PrimaryColor.Green) + "%"); 
     System.out.println(TransportMedium.Air + " " + ParentUtil.pctOf(TransportMedium.Air) + "%"); 
    } 


} 

interface Parent<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> { 
    Class<C> getChildClass(); 

    EnumSet<C> getChildren(); 
} 

interface Child<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> { 
    Class<P> getParentClass(); 

    P getParent(); 
} 

enum PrimaryColor implements Parent<PrimaryColor, PastelColor> { 
    Red, Green, Blue; 

    private EnumSet<PastelColor> children; 

    public Class<PastelColor> getChildClass() { 
     return PastelColor.class; 
    } 

    public EnumSet<PastelColor> getChildren() { 
     if(children == null) children=ParentUtil.loadChildrenOf(this); 
     return children; 
    } 
} 

enum PastelColor implements Child<PrimaryColor, PastelColor> { 
    Pink(PrimaryColor.Red), HotPink(PrimaryColor.Red), // 
    Rockmelon(PrimaryColor.Green), // 
    SkyBlue(PrimaryColor.Blue), BabyBlue(PrimaryColor.Blue); 

    final PrimaryColor parent; 

    private PastelColor(PrimaryColor parent) { 
     this.parent = parent; 
    } 

    public Class<PrimaryColor> getParentClass() { 
     return PrimaryColor.class; 
    } 

    public PrimaryColor getParent() { 
     return parent; 
    } 
} 

enum TransportMedium implements Parent<TransportMedium, Vehicle> { 
    Land, Sea, Air; 

    private EnumSet<Vehicle> children; 

    public Class<Vehicle> getChildClass() { 
     return Vehicle.class; 
    } 

    public EnumSet<Vehicle> getChildren() { 
     if(children == null) children=ParentUtil.loadChildrenOf(this); 
     return children; 
    } 
} 

enum Vehicle implements Child<TransportMedium, Vehicle> { 
    Car(TransportMedium.Land), Truck(TransportMedium.Land), // 
    BigBoat(TransportMedium.Sea), LittleBoat(TransportMedium.Sea), // 
    JetFighter(TransportMedium.Air), HotAirBaloon(TransportMedium.Air); 

    private final TransportMedium parent; 

    private Vehicle(TransportMedium parent) { 
     this.parent = parent; 
    } 

    public Class<TransportMedium> getParentClass() { 
     return TransportMedium.class; 
    } 

    public TransportMedium getParent() { 
     return parent; 
    } 
} 

class ParentUtil { 
    private ParentUtil(){} 
    static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> // 
    float pctOf(P parent) { 
     return (float) parent.getChildren().size()/// 
       (float) EnumSet.allOf(parent.getChildClass()).size() // 
       * 100f; 
    } 
    public static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> // 
    EnumSet<C> loadChildrenOf(P p) { 
     EnumSet<C> cc = EnumSet.noneOf(p.getChildClass()); 
     for(C c: EnumSet.allOf(p.getChildClass())) { 
      if(c.getParent() == p) { 
       cc.add(c); 
      } 
     } 
     return cc; 
    } 
} 
  0

Ce n'est pas vraiment une question, mais cela peut valoir la peine de reformuler une question que vous répondez vous-même afin que nous puissions voter. 22 févr.. 092009-02-22 07:57:58

  0

Ce n'est pas une question, mais je pense qu'il y a une place pour quelque chose sur SO. Je sais que Jeff n'aime pas l'idée, donc vous pourriez être flambé. 22 févr.. 092009-02-22 08:12:23

  0

Je suis d'accord avec les commentaires précédents, il vaudrait mieux que ce soit écrit en tant que question (rappelez-vous que vous pouvez répondre à vos propres questions). 22 févr.. 092009-02-22 08:24:19

+2

Je ne suis pas d'accord que SO est l'endroit pour ce genre de chose. C'est vraiment un article de blog. Si cela peut être écrit comme une question, écrivez la question - si c'est une bonne solution, elle sera votée, s'il y a une meilleure solution, elle ne le sera pas. -1 J'ai peur, et je voterais pour fermer si je le pouvais. 22 févr.. 092009-02-22 09:01:50

  0

Question non trouvée? 22 févr.. 092009-02-22 11:27:11

  0

@Nick Fortescue Jeff a dit qu'il voulait créer un espace pour les personnes qui n'étaient pas enclines à bloguer pour partager leurs connaissances. 22 févr.. 092009-02-22 12:58:26

  0

@IainMH - Je sais, mais pour des réponses aux questions. Jeff écrit toujours des billets de blog.Celui-ci est assez proche de la limite, mais je pense que si l'auteur ne peut pas réécrire comme une question, alors il devrait être fermé. Si c'est ce à quoi le SO est destiné, il peut être reformulé comme une question. 22 févr.. 092009-02-22 22:16:15

  0

Est-ce que la question - quelle est la question? 25 févr.. 092009-02-25 11:17:52

  0

Eh bien, je ne bloque pas parce que je ne suis pas assez cool pour avoir quelque chose d'intéressant à dire tous les jours. Ou semaine. Donc je l'ai fait comme un post. 28 févr.. 092009-02-28 02:54:35

  0

Ce serait bien si libellé comme réponse à une question. 27 juil.. 112011-07-27 21:21:59

1

Vous pouvez simplement utiliser la mise en œuvre Commons Enum à la place:

http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/enums/Enum.html

qui vous permet de créer de Enum qui peuvent ensuite être sous-.

  0

Enums réels ont des avantages, comme la possibilité de passer() sur eux. 11 juil.. 092009-07-11 03:28:33

  0

Les enums réels sont également gérés spécialement par la sérialisation java. 16 févr.. 112011-02-16 08:08:43


0

c'est plus simple, fait-il ce que vous voulez?

import java.util.*; 
interface Tree{ 
    Tree parent(); 
    Set<Tree> children(); 
} 
enum PrimaryColor implements Tree { 
    Red,Green,Blue; 
    @Override public Tree parent() { 
     return null; 
    } 
    @Override public Set<Tree> children() { 
     return Collections.unmodifiableSet(children); 
    } 
    final Set<Tree> children=new LinkedHashSet<Tree>(); 
} 
enum PastelColor implements Tree { 
    Pink(PrimaryColor.Red),HotPink(PrimaryColor.Red),Rockmelon(PrimaryColor.Green),SkyBlue(PrimaryColor.Blue),BabyBlue(PrimaryColor.Blue); 
    PastelColor(final PrimaryColor primaryColor) { 
     this.primaryColor=primaryColor; 
     if (primaryColor!=null) primaryColor.children.add(this); 
    } 
    @Override public Tree parent() { 
     return primaryColor; 
    } 
    @Override public Set<Tree> children() { 
     return Collections.emptySet(); 
    } 
    double percent() { 
     return primaryColor.children().size()*100./EnumSet.allOf(super.getClass()).size(); 
    } 
    private final PrimaryColor primaryColor; 
} 
public class Main{ 
    static double percent(final Tree tree) { 
     final Tree parent=tree.parent(); 
     if (tree instanceof Enum) { return parent.children().size()*100./((Enum)tree).getClass().getEnumConstants().length; } 
     else throw new RuntimeException("strange tree!"); 
    } 
    public static void main(String[] args) { 
     System.out.println("one way"); 
     for(PastelColor pastelColor:PastelColor.values()) 
      System.out.println(pastelColor+" "+pastelColor.percent()); 
     System.out.println("another way"); 
     for(PastelColor pastelColor:PastelColor.values()) 
      System.out.println(pastelColor+" "+percent(pastelColor)); 
    } 
} 
  0

Le point n'est pas d'avoir à envoyer des choses à Enum - pour le faire sécuriser lors de la compilation. 22 juin. 112011-06-22 03:25:41