代码之家  ›  专栏  ›  技术社区  ›  I82Much

具有泛型类型边界的Java Builder模式

  •  5
  • I82Much  · 技术社区  · 15 年前

    我正试图创建一个具有许多参数的类,使用构建器模式而不是伸缩构造函数。我这样做是用Joshua Bloch的有效Java描述的,在封闭类上拥有私有构造函数,以及公共静态Builder类。builder类在调用build()之前确保对象处于一致状态,此时它将封闭对象的构造委托给私有构造函数。因此

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

    这里的units参数不是 Unit<Acceleration> 但是 Unit<Length> 但它仍然被编译器接受。

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

    2 回复  |  直到 15 年前
        1
  •  7
  •   Daniel Martin    15 年前

    units 应该返回 Builder<Q> 不是没有活力的 Builder .

        2
  •  0
  •   Péter Török    15 年前

    虽然@daniel's point是有效的,但是Eclipse至少可以发现代码中的错误。当然,你对 Quantity , Unit METER 可能不同于我所说的简单的黑客:

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