GoF的原始Builder模式与Joshua Bloch的“修订的GoF Builder模式”有什么区别?
答案 0 :(得分:11)
GoF模式侧重于抽象构造步骤,以便通过改变构建器可以获得不同的结果,而“修订构建器”针对的是多个构造函数添加的不必要的复杂性问题。所以GoF模式更多的是关于抽象,修改后的模式更多的是关于简单性(IMO)。
查看http://en.wikipedia.org/wiki/Builder_pattern和http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html中的示例,应该非常清楚。
答案 1 :(得分:11)
注意重新Mikko's answer:Hansen's example有一些问题 - 或者至少与Bloch的版本存在差异,但我认为Bloch的版本更优越。
具体做法是:
首先,Widget
的字段在Builder.build()
而不是Widget
构造函数中设置,因此不是(也不可能)final
。据说Widget
是不可改变的,但没有什么可以阻止其他程序员出现并稍后添加setter。
其次,Hansen的构建方法中的评论说“预创建验证就在这里”。布洛赫(EJ 2ed.p.15)说:
在将参数从构建器复制到对象之后检查[不变量]并在对象字段而不是构建器字段(项目39)上检查它们是至关重要的。
如果你翻到第39项(第185页),你会看到推理:
[This]保护类免受在检查参数的时间和复制时间之间的“漏洞窗口”期间对另一个线程的参数的更改的影响。
Widget
中的字段是不可变的,不需要任何防御性复制,但是如果有人出现并添加Date
或数组,那么坚持正确的模式会更安全或者稍后可变Collection
。 (它还可以防止在Builder
调用过程中修改build()
的另一个线程,但这是一个非常狭窄的安全窗口,所以最好只确保Builder
不是public class Widget {
public static class Builder {
private String name;
private String model;
private String serialNumber;
private double price;
private String manufacturer;
public Builder( String name, double price ) {
this.name = name;
this.price = price;
}
public Widget build() {
Widget result = new Widget(this);
// *Post*-creation validation here
return result;
}
public Builder manufacturer( String value ) {
this.manufacturer = value;
return this;
}
public Builder serialNumber( String value ) {
this.serialNumber = value;
return this;
}
public Builder model( String value ) {
this.model = value;
return this;
}
}
private final String name;
private final String model;
private final String serialNumber;
private final double price;
private final String manufacturer;
/**
* Creates an immutable widget instance.
*/
private Widget( Builder b ) {
this.name = b.name;
this.price = b.price;
this.model = b.model;
this.serialNumber = b.serialNumber;
this.manufacturer = b.manufacturer;
}
// ... etc. ...
}
在线程之间共享。)
更像Blochlike的版本将是:
Widget
所有final
字段现在都是{{1}},所有字段都在构建后验证。