什么是修订后的构建模式?

maa*_*nus 16 java design-patterns

GoF的原始Builder模式与Joshua Bloch的"修订后的GoF Builder模式"有什么区别?

Mik*_*man 11

GoF模式侧重于抽象构造步骤,以便通过改变构建器可以获得不同的结果,而"修订构建器"针对多个构造函数添加的不必要复杂性的问题.所以GoF模式更多的是关于抽象,修改后的模式更多的是简单性(IMO).

请查看http://en.wikipedia.org/wiki/Builder_patternhttp://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html中的示例,它应该非常清楚.


Dav*_*les 11

请注意Mikko的回答:Hansen的例子有一些问题 - 或者至少与Bloch的版本存在差异,尽管我认为Bloch的版本更优越.

特别:

首先,Widget字段是在构造函数中Builder.build()而不是在Widget构造函数中设置的,因此不是(也可能不是)final.Widget据说是不可改变的,但没有什么可以阻止其他程序员出现并稍后添加setter.

其次,Hansen的构建方法中的评论说"预创建验证就在这里".布洛赫(EJ 2ed.p.15)说:

在将参数从构建器复制到对象之后检查[不变量]并在对象字段而不是构建器字段(项目39)上检查它们是至关重要的.

如果你翻到第39项(第185页),你会看到推理:

[This]保护类在检查参数的时间和复制时间之间的"漏洞窗口"期间防止来自另一个线程的参数的更改.

这些字段Widget是不可变的,不需要任何防御性复制,但是只要坚持正确的模式就更安全了,以防有人出现并添加一个Date或一个数组或Collection稍后可变.(它还可以防止另一个线程Builder在调用过程中修改build(),但这是一个非常狭窄的安全窗口,因此最好只确保Builder线程之间不共享s.)

更像Blochlike的版本将是:

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. ...
}
Run Code Online (Sandbox Code Playgroud)

所有Widget字段现在都是final,所有字段都在构建后进行验证.