以下是争论在 Java 中使用该模式和示例代码的一些原因,但它是 Design Patterns 中的四人帮所涵盖的构建器模式的实现。您在 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模式,您可以在其中调用具有强制参数的构造器,然后在之后调用任何可选的设置器:
Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);
这里的问题是,由于对象是通过多次调用创建的,因此它在构造过程中可能处于不一致的状态。这也需要大量额外的努力来确保线程安全。 p>
更好的选择是使用构建器模式。
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 实践的更多信息我强烈推荐它。