How to create an immutable builder of an immutable class that contains a set?

时间秒杀一切 提交于 2019-12-23 04:11:10

问题


I am trying to create an immutable builder of an immutable class that contains a Set. It should be an immutable set really but for now I have to use the regular JCF classes. Using the standard pizza example, I have the pizza base as a mandatory parameter and toppings as optional, 0 or more allowed. I imagine that each call to addToppings() will create a new immutable builder with a set of toppings and then finally when build is called the Pizza object will be delivered. I just don't know how to build up the immutable set of toppings. Here is my code:

public class Pizza {

private Pizza(Base base, Set<Topping> toppings) {
    this.base = base;
    this.toppings = toppings;
}

public static PizzaBuilder createBuilder(Base pizzaBase) {
    return new PizzaBuilder(new Pizza(pizzaBase, null));
}

public static class PizzaBuilder {
    private PizzaBuilder(Pizza pizza) {
        this.pizza = pizza;
    }

    public PizzaBuilder addTopping(Topping topping) {
        return new PizzaBuilder(new Pizza(pizza.base, ???));
    }

    public Pizza build() {
        return pizza;
    }

    final private Pizza pizza;
}

public Collection<Topping> getToppings() {
    return Collections.unmodifiableSet(toppings);
}

enum Base {DEEP_PAN, THIN}
enum Topping {MOZZARELLA, TOMATO, ANCHOVIES, PEPPERONI}

final private Base base;
final private Set<Topping> toppings;

}

I know this is a deviation from the 'standard' new builder pattern but I find the storing and copying of values there inelegant because the target class already defines what fields are needed.


回答1:


public PizzaBuilder addTopping(Topping topping) {
    Set<Topping> toppings = null;
    if (pizza.toppings == null)
        toppings = new LinkedHashSet<Topping>();
    else
        toppings = new LinkedHashSet<Topping>(pizza.toppings);
    toppings.add(topping);
    return new PizzaBuilder(new Pizza(pizza.base, toppings));
}

Is that what you're interested in? I chose LinkedHashSet to maintain the order of the toppings.




回答2:


You could clone the old set, add the new entry, and then use that one. EnumSet is more efficient than Set by the way:

final private EnumSet<Topping> toppings;

public PizzaBuilder addTopping(Topping topping) {
    EnumSet<Topping> newToppings = EnumSet.of(topping);
    if (toppings != null) {
        newToppings.addAll(toppings);
    }
    return new PizzaBuilder(new Pizza(pizza.base, newToppings));
}

Please note this isn't thread save.

Java doesn't have 'real' immutable sets (where adding or removing elements returns a new set, similar to the String methods in Java), but Scala has.



来源:https://stackoverflow.com/questions/5396534/how-to-create-an-immutable-builder-of-an-immutable-class-that-contains-a-set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!