你什么时候使用Builder模式?

什么是使用Builder模式的常见实例? 它会给你买什么? 为什么不使用工厂模式?


建设者和工厂恕我直言之间的关键区别是,当你需要做很多事情来建立一个对象时,建造者是有用的。 例如想象一个DOM。 您必须创建大量节点和属性才能获得最终对象。 工厂可以在一个方法调用中轻松创建整个对象时使用工厂。

使用构建器的一个例子是构建一个XML文档,我在构建HTML片段时使用了这个模型,例如,我可能有一个用于构建特定类型表的Builder,它可能具有以下方法(参数未显示)

BuildOrderHeaderRow()
BuildLineItemSubHeaderRow()
BuildOrderRow()
BuildLineItemSubRow()

然后这个构建者会为我吐出HTML。 这是更容易阅读,然后通过一个大的程序方法。

查看维基百科上的Builder图案。


以下是争论在Java中使用模式和示例代码的一些原因,但它是四人帮在设计模式中涵盖的Builder模式的实现。 您在Java中使用它的原因也适用于其他编程语言。

正如Joshua Bloch在Effective Java,2nd Edition中所述:

当设计构造函数或静态工厂只有少数参数的类时,构建器模式是一个很好的选择。

我们都在某个时候遇到了一个具有构造函数列表的类,其中每个添加都添加了一个新的选项参数:

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

这被称为Telescoping构造函数模式。 这种模式的问题在于,一旦构造函数的参数长度为4或5个参数,就很难记住所需的参数顺序以及在特定情况下可能需要的特定构造函数。

Telescoping构造函数模式的一个替代方法JavaBean模式 ,您可以使用强制参数调用构造函数,然后在调用任何可选的setter方法之后:

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

这里的问题在于,因为该对象是通过多次调用创建的,所以它可能在其构造中处于不一致的状态。 这还需要很多额外的努力来确保线程安全。

更好的选择是使用Builder模式。

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;
  }
}

请注意, Pizza是不可变的,参数值都在一个位置 。 因为Builder的setter方法返回Builder对象,所以它们可以被链接

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

这导致代码易于编写,并且易于阅读和理解。 在这个例子中, 可以修改构建方法,以便在参数从构建器复制到Pizza对象后检查参数, 并在提供了无效参数值时抛出IllegalStateException。 这种模式非常灵活,未来可以添加更多参数。 如果您将要构造函数的参数超过4个或5个,它才真正有用。 也就是说, 如果您怀疑您未来可能会添加更多参数,首先它可能是值得的。

我从Joshua Bloch的Effective Java,2nd Edition一书中大量借鉴了这个主题。 要更多地了解这种模式和其他有效的Java实践, 我强烈推荐它。


考虑一家餐馆。 “今天的餐”的创建是一种工厂模式,因为你告诉厨房“让我吃今天的饭”,厨房(工厂)根据隐藏标准决定产生什么对象。

如果您订购自定义披萨,建造者就会出现。 在这种情况下,服务员告诉厨师(建造者):“我需要比萨饼,加入奶酪,洋葱和培根!” 因此,构建器会暴露生成的对象应具有的属性,但会隐藏如何设置它们。

链接地址: http://www.djcxy.com/p/50055.html

上一篇: When would you use the Builder Pattern?

下一篇: estimation of subpixel values from images in Python