Question

J'essaie de créer une classe avec de nombreux paramètres, en utilisant un motif de générateur plutôt que des constructeurs télescopiques. Je fais cela de la manière décrite par Java Java de Joshua Bloch, ayant un constructeur privé sur la classe d'encluse, et une classe publique Static Builder. La classe Builder garantit que l'objet est dans un état cohérent avant d'appeler Build (), auquel cas il délègue la construction de l'objet entorant au constructeur privé. Ainsi

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

    }

}

Je veux ensuite ajouter des limites de type à certaines variables, et j'ai donc besoin de paramétriser la définition de classe. Je veux que les limites de la classe FOO soient les mêmes que celles de la classe 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);
        }

    }

}

Cela se compile bien, mais le compilateur me permet de faire des choses que je ressens devrait être des erreurs de compilateur. Par exemple

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

Ici, l'argument des unités n'est pas Unit<Acceleration> mais Unit<Length>, mais il est toujours accepté par le compilateur.

Qu'est-ce que je fais de mal ici? Je veux m'assurer au temps de compilation que les types d'unités correspondent correctement.

Était-ce utile?

La solution

units devrait revenir Builder<Q>, pas un non-générifié Builder.

Autres conseils

Bien que le point de @ Daniel soit valide, l'erreur de votre code est toujours repérée par Eclipse au moins. Bien sûr, votre définition de Quantity, Unit et METER est probablement différent du hack simpliste que j'ai mis en place:

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

Le message d'erreur est:

The method units(Unit<Acceleration>) in the type Foo.Builder<Acceleration> is
not applicable for the arguments (Unit<Length>)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top