Sugerencia de codificación: tipos de intersección y enums Java


8

Los tipos de intersección le permiten (algo así) hacer enumeraciones que tienen una jerarquía de herencia. No puede heredar la implementación, pero puede delegarla en una clase auxiliar.

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

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

Esto es útil cuando tiene un número de enumeraciones diferentes que implementan algún tipo de patrón. Por ejemplo, un número de pares de enumeraciones que tienen una relación padre-hijo.

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

Puede escribir métodos genéricos que decir "Ok, dado un valor de enumeración eso es uno de los padres de algunos otros valores de enumeración, ¿qué porcentaje de todas las posibles enumeraciones secundarios del tipo hijo tiene este valor padres particular por lo que sus padres ? ", y tenerlo todo seguro y hecho sin lanzar. (por ejemplo: que "Mar" es el 33% de todos los vehículos posibles, y "Verde" el 20% de todos los Pasteles posibles).

El código tiene este aspecto. Nótese en particular que las clases de "hoja" en sí mismas son bastante ordenadas, pero las clases genéricas tienen declaraciones horriblemente feas. Está bien: solo los escribes una vez. Una vez que las clases genéricas están allí, entonces usarlas es fácil.

La clase de ayuda siguiente solo tiene algunos métodos estáticos. Otras maneras de ir incluir

  • proporcionar una instancia que devuelve un conjunto unitario , pero escriben de acuerdo con el padre/hijo
  • devolver una instancia para cada paren/niño, mecanografiado apropiadamente, e incluyendo una en cada una enumeración de los padres

Con esta segunda opción, el objeto "hijos" sería en realidad el interior del ayudante, lo que reduce la cantidad de código necesario en las enumeraciones. Todos crearían una instancia de ayuda y delegarían cualquier cosa difícil.

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

Esto no es realmente una pregunta, pero puede valer la pena reformularlo en una pregunta que responda usted mismo para que podamos votarla. 22 feb. 092009-02-22 07:57:58

  0

Esto no es una pregunta, pero sí creo que hay un lugar para cosas así en SO. Sé que a Jeff no le gusta la idea, así que es posible que te llame la atención. 22 feb. 092009-02-22 08:12:23

  0

Tengo que estar de acuerdo con los comentarios anteriores, sería mucho mejor tener esto escrito como una pregunta (recuerde que puede contestar sus propias preguntas). 22 feb. 092009-02-22 08:24:19

+2

No estoy de acuerdo con que SO sea el lugar para este tipo de cosas. Esta es realmente una publicación de blog. Si se puede escribir como una pregunta, luego escriba la pregunta: si esta es una buena solución, se votará, si hay una mejor solución, entonces no. -1 Temo, y votaría por cerrar si pudiera. 22 feb. 092009-02-22 09:01:50

  0

Pregunta no encontrada? 22 feb. 092009-02-22 11:27:11

  0

@Nick Fortescue Jeff dijo que quería crear SO como un lugar para que las personas que no estaban dispuestas a blog compartir sus conocimientos. 22 feb. 092009-02-22 12:58:26

  0

@IainMH - Lo sé, pero para las respuestas a las preguntas. Jeff todavía escribe publicaciones de blog.Esta es bastante cercana a la frontera, pero creo que si el autor no puede reescribirla como una pregunta, entonces debe cerrarse. Si es para lo que está destinado el SO, puede reformularse como una pregunta 22 feb. 092009-02-22 22:16:15

  0

. ¿La pregunta es cuál es la pregunta? 25 feb. 092009-02-25 11:17:52

  0

Bueno, no bloqueo porque no soy lo suficientemente bueno como para tener algo interesante que decir todos los días. O la semana. Así que hice esto como una publicación. 28 feb. 092009-02-28 02:54:35

  0

Esto estaría bien si se redactara como respuesta a una pregunta. 27 jul. 112011-07-27 21:21:59

1

Se podía utilizar la implementación de los Comunes de enumeración en su lugar:

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

que le permite crear de Enum que luego puede tener subclases.

  0

Las enumeraciones reales tienen beneficios, como la capacidad de cambiarlas(). 11 jul. 092009-07-11 03:28:33

  0

las enumeraciones reales también se manejan especialmente por serialización java. 16 feb. 112011-02-16 08:08:43


0

esto es más simple, ¿hace lo que quiere?

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

El punto no es tener que lanzar cosas a Enum, para tenerlo seguro en tiempo de compilación. 22 jun. 112011-06-22 03:25:41