什么时候使用Joshua Bloch的Builder实现?

时间:2013-09-09 21:45:28

标签: java design-patterns architecture

我想知道何时应该使用内部静态类的构建器和经典类的构建器吗?

Effective Java book

的实现
public class Pizza {
  private int size;
  private boolean cheese;
  private boolean pepperoni;
  private boolean bacon;

  public static class Builder {
    //required
    private final int size;

    //optional
    private boolean cheese = false;
    private boolean pepperoni = false;
    private boolean bacon = false;

    public Builder(int size) {
      this.size = size;
    }

    public Builder cheese(boolean value) {
      cheese = value;
      return this;
    }

    public Builder pepperoni(boolean value) {
      pepperoni = value;
      return this;
    }

    public Builder bacon(boolean value) {
      bacon = value;
      return this;
    }

    public Pizza build() {
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }
}

定期实施

(只是图表) enter image description here

2 个答案:

答案 0 :(得分:1)

当你准备好加倍努力使类构造函数看起来自然时,我会说

谁可以否认这看起来像好的代码

Pizza pizza = new Pizza.Builder(10).cheese(true).peperoni(true).bacon(true).build();

我的意思是......那不仅仅是甜蜜的吗?它甚至还有培根

第二个(也是更常见的)选项是:

Pizza pizza = new Pizza(10);
pizza.setCheese(true);
pizza.setPeperoni(true);
pizza.setBacon(true);

使用反射可以更容易地工作,因此可以更容易地进行序列化/反序列化 - 但是会遇到更麻烦和冗长的构造。

第三和最不灵活的是:

Pizza pizza = new Pizza(10, true, true, true);

但是可以同时提供第二和第三种机制,这可以是一个加号。

如何选择

没有简单的选择方法。如果您想吸引客户购买您的库,您可以提供所有三种方法,但这会破坏使用Builder(隐藏实际构造函数)的主要好处之一。

我建议使用第二种方法,也许第三种方法,除非有充分的理由采用不同寻常的使用Builder的方法。

答案 1 :(得分:1)

您应该考虑在 1时使用Builder模式。您需要防止对象进入不一致状态 AND 2。使用构造函数参数将难以使用/读取,因为您需要设置一些笨重(大量)的属性。

使用普通的默认构造函数+ getter / setter可能允许使用者进入无效/不一致状态。 I.E.他们可能忘记设置一个非常重要的属性(如奶酪),但他们不能这样做,并且无论如何都可以创建一个披萨,即使是在一个"坏"州。消费者负担在施工后适当地设置对象的状态。

您通常可以通过构造函数参数来阻止此操作。 E.G。

private Pizza() {}
public Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) 
{
    ...
}

但是当你有大量参数时,这可能很难读/写。

因此,总而言之,当您想要保证您的对象不能构建在一个不一致的状态时,您有太多的字段要设置,使用构造函数参数会使其难以使用和读取,您可以考虑使用Builder模式。