何时会使用生成器模式?[已关闭]

2022-08-31 04:14:42

使用生成器模式的一些常见真实示例有哪些?它能给你带来什么?为什么不直接使用工厂模式呢?


答案 1

以下是一些理由,主张在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) { ... }

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

伸缩构造函数模式的一种替代方法是 JavaBean 模式,在该模式中,您可以使用强制参数调用构造函数,然后在以下情况下调用任何可选的 setter:

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

这里的问题是,由于对象是通过多次调用创建的,因此在构造过程中它可能处于不一致的状态。这也需要大量的额外努力来确保线程安全。

更好的替代方法是使用生成器模式。

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 是不可变的,参数值全部位于一个位置。由于生成器的 setter 方法返回生成器对象,因此它们能够被链接

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

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

我从Joshua Bloch的《Effective Java, 2nd Edition》一书中大量借用了这个话题。要了解有关此模式和其他有效 Java 实践的更多信息,我强烈推荐它。


答案 2

考虑一家餐厅。“今天的饭菜”的创造是一种工厂模式,因为你告诉厨房“给我今天吃饭”,厨房(工厂)根据隐藏的标准决定要生成的对象。

如果您订购自定义披萨,则会显示构建器。在这种情况下,服务员告诉厨师(建筑商)“我需要一个比萨饼;加入奶酪、洋葱和培根!”因此,生成器公开生成的对象应具有的属性,但隐藏了如何设置这些属性。


推荐