Coding tip - tipi di intersezione e java enum


8

I tipi di intersezione consentono di eseguire (in qualche modo) enumerazioni con una gerarchia di ereditarietà. Non è possibile ereditare l'implementazione, ma è possibile delegarla a una classe helper.

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

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

Questo è utile quando si dispone di un numero di enumerazioni diverse che implementano una sorta di modello. Ad esempio, un numero di coppie di enumerazioni che hanno una relazione genitore-figlio.

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

È possibile scrivere metodi generici che dicono "Ok, dato un valore enum questo è un genitore di alcuni altri valori enum, qual è la percentuale di tutte le possibili enumerazioni secondari del tipo bambino ha questo valore padre particolare come impresa madre ? ", e avere tutto dattiloscritto e fatto senza casting. (ad esempio: "Sea" è il 33% di tutti i veicoli possibili e "Green" il 20% di tutti i possibili pastelli).

Il codice è simile a questo. Si noti in particolare che le classi "foglia" sono piuttosto ordinate, ma le classi generiche hanno dichiarazioni orribilmente brutte. Va bene: li scrivi solo una volta. Una volta che ci sono le classi generiche, utilizzarle è facile.

La classe helper di seguito ha solo alcuni metodi statici. Altri modi per andare includere

  • fornendo un'istanza che restituisce un singleton , ma digitati secondo il padre/figlio
  • restituire un'istanza per ogni paren/bambino, digitato modo appropriato, e di cui uno in ogni enum genitore

Con questa seconda opzione, l'oggetto "bambini" sarebbe in realtà all'interno del soccorritore, in modo da ridurre la quantità di codice necessario nelle enumerazioni. Tutti istanziavano un aiutante e delegavano qualcosa di 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

Questa non è davvero una domanda, ma potrebbe valere la re-formulazione di una domanda a cui rispondi tu stesso in modo che possiamo votarla. 22 feb. 092009-02-22 07:57:58

  0

Questa non è una domanda, ma penso che ci sia un posto per una cosa del genere su SO. So che a Jeff non piace l'idea, quindi potresti essere fiammeggiato. 22 feb. 092009-02-22 08:12:23

  0

Devo essere d'accordo con i commenti precedenti, sarebbe molto meglio avere questo scritto come una domanda (ricorda che puoi rispondere alle tue stesse domande). 22 feb. 092009-02-22 08:24:19

+2

Non sono d'accordo sul fatto che SO sia il posto giusto per questo genere di cose. Questo è davvero un post sul blog. Se può essere scritto come una domanda, scrivi la domanda: se questa è una buona soluzione, verrà votata, se c'è una soluzione migliore allora non lo sarà. -1 Ho paura, e voterei per chiudere se potessi. 22 feb. 092009-02-22 09:01:50

  0

Domanda non trovata? 22 feb. 092009-02-22 11:27:11

  0

@Nick Fortescue Jeff ha detto che voleva creare SO come luogo per persone che non erano inclini al blog a condividere le proprie conoscenze. 22 feb. 092009-02-22 12:58:26

  0

@IainMH - Lo so, ma per le risposte alle domande. Jeff scrive ancora post sul blog.Questo è abbastanza vicino al confine, ma penso che se l'autore non può riscrivere come una domanda, allora dovrebbe essere chiuso. Se è ciò che SO è pensato per, può essere riformulato come una domanda 22 feb. 092009-02-22 22:16:15

  0

è la domanda - qual è la domanda? 25 feb. 092009-02-25 11:17:52

  0

Beh, non blocco perché non sono abbastanza bello da avere qualcosa di interessante da dire ogni giorno. O settimana. Quindi l'ho fatto come post. 28 feb. 092009-02-28 02:54:35

  0

Questo andrebbe bene se formulato come risposta a una domanda. 27 lug. 112011-07-27 21:21:59

1

Si potrebbe utilizzare l'attuazione Commons Enum invece:

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

, che permette di creare di Enum, che possono poi essere sottoclasse.

  0

I veri enumerati hanno comunque dei vantaggi, come la possibilità di cambiare() su di essi. 11 lug. 092009-07-11 03:28:33

  0

le enumerazioni reali sono anche gestite specialmente dalla serializzazione java. 16 feb. 112011-02-16 08:08:43


0

questo è più semplice, fa quello che vuoi?

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

Il punto non è il dover gettare le cose su Enum - per farlo sicuro in fase di compilazione. 22 giu. 112011-06-22 03:25:41