首页 文章

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

提问于
浏览
5

我正在尝试使用Builder模式而不是telescoping构造函数创建一个包含许多参数的类 . 我是按照Joshua Bloch的Effective 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();

这里的单位参数不是 Unit<Acceleration> 而是 Unit<Length> ,但它仍然被编译器接受 .

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

2 回答

  • 7

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

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

相关问题