What's the revised builder pattern?

后端 未结 2 1051
半阙折子戏
半阙折子戏 2020-12-29 08:29

What is the difference between the original Builder pattern by GoF and the \"revised GoF Builder pattern\" by Joshua Bloch?

相关标签:
2条回答
  • 2020-12-29 08:58

    The GoF pattern focuses on abstracting the steps of construction so that by varying the builder you can get different results while the "revised builder" is targeting the problem of unnecessary complexity added by multiple constructors. So the GoF pattern is more about abstraction and the revised patter is more about simplicity (IMO).

    Look at the examples in http://en.wikipedia.org/wiki/Builder_pattern and http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html and it should be quite clear.

    0 讨论(0)
  • 2020-12-29 09:25

    Note re Mikko's answer: Hansen's example has a few problems -- or, at least, differences from Bloch's version, though I'm of the opinion Bloch's version is superior.

    Specifically:

    First, Widget's fields are set in Builder.build() rather than in the Widget constructor, and therefore aren't (and can't be) final. Widget is said to be immutable, but there's nothing to discourage another programmer from coming along and adding setters later.

    Second, comments in Hansen's build method say "pre-creation validation goes here". Bloch (EJ 2ed. p.15) says:

    It is critical that [the invariants] be checked after copying the parameters from the builder to the object, and that they be checked on the object fields rather than the builder fields (Item 39).

    If you flip to Item 39 (p. 185) you see the reasoning:

    [This] protects the class against changes to the parameters from another thread during the "window of vulnerability" between the time the parameters are checked and the time they are copied.

    The fields in Widget are immutable and don't require any defensive copying, but nonetheless it's safer just to stick to the correct pattern, in case someone comes along and adds a Date or an array or some mutable Collection later. (It also protects against another thread modifying the Builder in the middle of a call to build(), but that's a pretty narrow window of safety so it's probably best just to make sure Builders aren't shared between threads.)

    A more Blochlike version would be:

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

    All Widget fields are now final, and all are validated after construction.

    0 讨论(0)
提交回复
热议问题