How to create an immutable builder of an immutable class that contains a set?
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.
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.
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.
精彩评论