2010-05-17 95 views
5

我试图用许多参数创建一个类,使用Builder模式而不是伸缩构造函数。我按照Joshua Bloch的Effective Java描述的方式进行操作,在封闭类上有私有构造函数,还有一个公共静态生成器类。在调用build()之前,Builder类确保对象处于一致状态,此时它将封闭对象的构造委托给私有构造函数。因此,具有泛型类型边界的Java生成器模式

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

    } 

} 

然后,我想添加类型边界的一些变量,因此需要参数化类定义。我希望Foo类的边界与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); 
     } 

    } 

} 

这个编译好,但编译器允许我做的事情,我觉得应该是编译器错误。例如。

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

这里单位的说法是不Unit<Acceleration>但​​,但它仍然是由编译器所接受。

我在这里做错了什么?我想在编译时确保单元类型正确匹配。

回答

6

units应该返回Builder<Q>,而不是一个ungenerified Builder

+0

谢谢你,我没有想到的很清楚这方面。 – I82Much 2010-05-17 22:39:37

0

尽管@ Daniel的观点是有效的,但是至少在Eclipse中发现代码中的错误。当然,你的QuantityUnitMETER定义是从简单的黑客我放在一起可能不同:

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(); 

的错误信息是:

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

有趣。我使用的是NetBeans,并没有抱怨。我使用的单位等级体系来自JSR 275(http://download.java.net/maven/2/net/java/dev/jsr-275/jsr-275/1.0-beta-2/)和JScience (http://jscience.org/) – I82Much 2010-05-17 23:32:54

+2

即使在NetBeans中,你也应该得到这个错误......如果不是的话,那是一个非常糟糕的错误。原始代码的区别在于你有一个中间属性:新的Foo.Builder ()。cheese(GOUDA).units(Unit.METER),其中'cheese'方法返回Builder Builder Builder 。 – Cowan 2010-05-18 02:04:42