mercredi 26 mai 2021

how generic type with a recursive type parameter along with the abstract self method allows method chaining to work properly?

I am reading Effective Java Edition 3. in chapter 2 page 14, the author talks about the builder pattern and presents this code:

public abstract class Pizza {
    public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE }
    final Set<Topping> toppings;
    abstract static class Builder<T extends Builder<T>> {
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }
        abstract Pizza build();
        // Subclasses must override this method to return "this"
        protected abstract T self();
    }
    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone(); // See Item 50
    }
}

an implementation of above abstract class:

public class NyPizza extends Pizza {
    public enum Size { SMALL, MEDIUM, LARGE }
    private final Size size;
    public static class Builder extends Pizza.Builder<Builder> {
        private final Size size;
        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }
        @Override public NyPizza build() {
            return new NyPizza(this);
        }
        @Override protected Builder self() { return this; }
    }
    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}

and we can use code like this:

NyPizza pizza = new NyPizza.Builder(SMALL)
.addTopping(SAUSAGE).addTopping(ONION).build();

quote from the book:

Note that Pizza.Builder is a generic type with recursive type parameter. this, along with the abstract self method, allows method chaining to work properly in subclasses, without the need for casts.

now my question is what power/value <T extends Builder<T>> added to Pizza class and how it is different with <T extends Builder>? if you are going to explain <T extends Builder<T>> to a five years old kid in simple English how would you explain it?

and I can't figure out the purpose of abstract self method in the super class?

Aucun commentaire:

Enregistrer un commentaire