2010-05-17 14 views
5

Estoy intentando crear una clase con muchos parámetros, utilizando un patrón de generador en lugar de constructores telescópicos. Estoy haciendo esto de la manera descrita por Effective Java de Joshua Bloch, con un constructor privado en la clase adjunta y una clase de generador estático público. La clase Builder garantiza que el objeto esté en un estado constante antes de llamar a build(), en cuyo punto delega la construcción del objeto adjunto al constructor privado. Por lo tantoPatrón de Java Builder con límites de tipo genérico

public class Foo { 

    // Many variables 

    private Foo(Builder b) { 
     // Use all of b's variables to initialize self 
    } 

    public static final class Builder { 

     public Builder(/* required variables */) { 

     } 

     public Builder var1(Var var) { 
      // set it 
      return this; 
     } 

     public Foo build() { 
      return new Foo(this); 
     } 

    } 

} 

Entonces quiero añadir límites tipo de algunas de las variables, y por lo tanto necesitan para parametrizar la definición de clase. Quiero que los límites de la clase Foo sean los mismos que los de la clase Builder.

public class Foo<Q extends Quantity> { 

    private final Unit<Q> units; 
    // Many variables 

    private Foo(Builder<Q> b) { 
     // Use all of b's variables to initialize self 
    } 

    public static final class Builder<Q extends Quantity> { 
     private Unit<Q> units; 

     public Builder(/* required variables */) { 

     } 

     public Builder units(Unit<Q> units) { 
      this.units = units; 
      return this; 
     } 

     public Foo build() { 
      return new Foo<Q>(this); 
     } 

    } 

} 

Esto compila bien, pero el compilador me permite hacer cosas que creo que deberían ser errores del compilador. P.ej.

public static final Foo.Builder<Acceleration> x_Body_AccelField = 
     new Foo.Builder<Acceleration>() 
     .units(SI.METER) 
     .build(); 

Aquí el argumento de unidades no es Unit<Acceleration> pero Unit<Length>, pero todavía es aceptado por el compilador.

¿Qué estoy haciendo mal aquí? Quiero asegurarme en tiempo de compilación de que los tipos de unidades coinciden correctamente.

Respuesta

6

units debe devolver Builder<Q>, no es un 0generified Builder.

+0

Gracias, yo no estaba pensando muy claramente en ese respeto. – I82Much

0

Aunque el punto de @ Daniel es válido, al menos Eclipse detecta el error en su código. Por supuesto, su definición de Quantity, Unit y METER es probablemente diferente de la corte simplista que arme:

interface Quantity { 
} 
class Acceleration implements Quantity { 
} 
class Length implements Quantity { 
} 
public class Unit<Q extends Quantity> { 
    public static final Unit<Length> METER = new Unit<Length>(); 
} 

public static final Foo.Builder<Acceleration> x_Body_AccelField = 
    new Foo.Builder<Acceleration>() 
    .units(Unit.METER) // here the compiler complains 
    .build(); 

El mensaje de error es:

The method units(Unit<Acceleration>) in the type Foo.Builder<Acceleration> is 
not applicable for the arguments (Unit<Length>) 
+0

Interesante. Estaba usando NetBeans, que no se quejó. La jerarquía de unidades que utilizo viene de JSR 275 (http://download.java.net/maven/2/net/java/dev/jsr-275/jsr-275/1.0-beta-2/) y JScience (http://jscience.org/) – I82Much

+2

Debería obtener ese error incluso en NetBeans ... si no, es un error muy malo. La diferencia en el código original es si tiene una propiedad intermedia: nuevas unidades Foo.Builder (). Cheese (GOUDA) (Unit.METER), donde el método 'cheese' devuelve Builder no Builder . – Cowan

Cuestiones relacionadas