我正在尝试创建一个包含Set的不可变类的不可变构建器。它应该是一个不可变的集合,但是现在我必须使用常规的JCF类。使用标准披萨示例,我将披萨基础作为必需参数,并将浇头作为可选,允许使用0或更多。我想每次调用addToppings()
都会创建一个带有一组浇头的新的不可变构建器,然后最终在调用构建时,将传递Pizza对象。我只是不知道如何构建toppings
的不可变集。这是我的代码:
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;
}
我知道这是对“标准”新构建器模式的偏离,但我发现存储和复制值不合适,因为目标类已经定义了所需的字段。
答案 0 :(得分:3)
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));
}
这是你感兴趣的吗?我选择了LinkedHashSet来维护浇头的顺序。
答案 1 :(得分:1)
您可以克隆旧集,添加新条目,然后使用该条目。顺便说一下,EnumSet
比Set
效率更高:
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));
}
请注意,这不是线程保存。
Java没有“真正的”不可变集合(添加或删除元素会返回一个新集合,类似于Java中的String方法),但是Scala has。