问题
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