如何创建包含集合的不可变类的不可变构建器?

时间:2011-03-22 19:11:14

标签: java design-patterns builder

我正在尝试创建一个包含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;

}

我知道这是对“标准”新构建器模式的偏离,但我发现存储和复制值不合适,因为目标类已经定义了所需的字段。

2 个答案:

答案 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)

您可以克隆旧集,添加新条目,然后使用该条目。顺便说一下,EnumSetSet效率更高:

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