Coding Tip - Kreuzungstypen und Java-Enums


8

Intersection-Typen ermöglichen es Ihnen, Sortierungen mit einer Vererbungshierarchie durchzuführen. Sie können die Implementierung nicht erben, aber Sie können sie an eine Hilfsklasse delegieren.

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

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

Dies ist nützlich, wenn Sie eine Reihe verschiedener Enums haben, die eine Art Muster implementieren. Zum Beispiel eine Anzahl von Paaren von Enums, die eine Eltern-Kind-Beziehung haben.

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

Sie können generische Methoden schreiben, die „Ok, da ein ENUM-Wert das ist ein Elternteil von einigen anderen ENUM-Werte sagen, wie viel Prozent aller möglichen Kind Aufzählungen des Kindes Art dieses bestimmten Stamm Wert als ihre Eltern haben ? ", und haben es alle typsicher und ohne Casting getan. (zB: "Sea" ist 33% aller möglichen Fahrzeuge und "Green" 20% aller möglichen Pastels).

Der Code sieht so aus. Beachten Sie insbesondere, dass die "Blatt" -Klassen selbst recht ordentlich sind - aber die generischen Klassen haben schrecklich hässliche Deklarationen. Das ist in Ordnung: Sie schreiben sie nur einmal. Sobald die generischen Klassen vorhanden sind, ist es einfach, sie zu verwenden.

Die Hilfsklasse unten hat nur einige statische Methoden. Andere Wege gehen zu

  • umfassen eine Instanz an, die eine Singleton zurückgibt, aber getippt nach dem Eltern/Kind
  • eine Instanz für jeden paren/Kind zurückkehrt, getippt angemessen, und darunter eine in jeder Elternteil enum

Mit dieser zweiten Option, die „Kinder“ Objekt würde innerhalb der Helfer tatsächlich sein, so die Menge an Code in den Aufzählungen benötigt reduzieren. Sie würden alle einen Helfer instantiieren und alles Schwierige delegieren.

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

Das ist nicht wirklich eine Frage, aber es kann in eine Frage wert Phrasierung Wieder sein, die Sie selbst beantworten, damit wir sie abstimmen werden. 22 feb. 092009-02-22 07:57:58

  0

Das ist keine Frage, aber ich denke, es gibt einen Platz für etwas auf SO. Ich weiß, dass Jeff die Idee nicht mag, also könntest du geflammt werden. 22 feb. 092009-02-22 08:12:23

  0

Ich muss den vorherigen Kommentaren zustimmen, es wäre viel besser, dies als Frage aufzuschreiben (denken Sie daran, dass Sie Ihre eigenen Fragen beantworten können). 22 feb. 092009-02-22 08:24:19

+2

Ich stimme nicht zu, dass SO der Ort für so etwas ist. Dies ist wirklich ein Blogbeitrag. Wenn es als Frage geschrieben werden kann, dann schreibe die Frage - wenn das eine gute Lösung ist, wird es gewählt, wenn es eine bessere Lösung gibt, dann wird es nicht stimmen. -1 Ich habe Angst, und ich würde schließen, wenn ich könnte. 22 feb. 092009-02-22 09:01:50

  0

Frage nicht gefunden? 22 feb. 092009-02-22 11:27:11

  0

@Nick Fortescue Jeff sagte, dass er SO als einen Ort für Leute schaffen wollte, die nicht dazu neigten, ihr Wissen zu teilen. 22 feb. 092009-02-22 12:58:26

  0

@IainMH - Ich weiß, aber für Antworten auf Fragen. Jeff schreibt immer noch Blogposts.Dieser ist ziemlich nah an der Grenze, aber ich denke, wenn der Autor nicht als eine Frage umschreiben kann, dann sollte es geschlossen werden. Wenn es das ist, wofür SO gemeint ist, kann es als eine Frage umformuliert werden 22 feb. 092009-02-22 22:16:15

  0

Ist die Frage - was ist die Frage? 25 feb. 092009-02-25 11:17:52

  0

Nun, ich blockiere nicht, weil ich einfach nicht cool genug bin, um jeden Tag etwas Interessantes zu sagen. Oder Woche. Also habe ich das als Post gemacht. 28 feb. 092009-02-28 02:54:35

  0

Dies wäre in Ordnung, wenn es als Antwort auf eine Frage formuliert wird. 27 jul. 112011-07-27 21:21:59

1

Sie könnten nur die Commons Enum-Implementierung verwenden statt:

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

, die Sie Enum ist erstellen können, die dann unterklassiert werden kann.

  0

Echte Enums haben jedoch Vorteile, wie die Fähigkeit, sie zu wechseln(). 11 jul. 092009-07-11 03:28:33

  0

echte Enums sind auch Griffe speziell von Java-Serialisierung. 16 feb. 112011-02-16 08:08:43


0

das ist einfacher, macht es was du willst?

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

Der Punkt ist nicht, Dinge zu Enum zu werfen - um es zur Kompilierzeit typsicher zu haben. 22 jun. 112011-06-22 03:25:41