15

Back in 2007, I read an article about Joshua Blochs take on the "builder pattern" and how it could be modified to improve the overuse of constructors and setters, especially when an object has a large number of properties, most of which are optional. A brief summary of this design pattern is articled here.

I liked the idea, and have been using it since. The problem with it, while it is very clean and nice to use from the client perspective, implementing it can be a pain in the bum! There are so many different places in the object where a single property is reference, and thus creating the object, and adding a new property takes a lot of time.

So...I had an idea. First, an example object in Joshua Bloch's style:

Josh Bloch Style:

public class OptionsJoshBlochStyle {

    private final String option1;
    private final int option2;
    // ...other options here  <<<<

    public String getOption1() {
        return option1;
    }

    public int getOption2() {
        return option2;
    }

    public static class Builder {

        private String option1;
        private int option2;
        // other options here <<<<<

        public Builder option1(String option1) {
            this.option1 = option1;
            return this;
        }

        public Builder option2(int option2) {
            this.option2 = option2;
            return this;
        }

        public OptionsJoshBlochStyle build() {
            return new OptionsJoshBlochStyle(this);
        }
    }

    private OptionsJoshBlochStyle(Builder builder) {
        this.option1 = builder.option1;
        this.option2 = builder.option2;
        // other options here <<<<<<
    }

    public static void main(String[] args) {
        OptionsJoshBlochStyle optionsVariation1 = new OptionsJoshBlochStyle.Builder().option1("firefox").option2(1).build();
        OptionsJoshBlochStyle optionsVariation2 = new OptionsJoshBlochStyle.Builder().option1("chrome").option2(2).build();
    }
}

Now my "improved" version:

public class Options {

    // note that these are not final
    private String option1;
    private int option2;
    // ...other options here

    public String getOption1() {
        return option1;
    }

    public int getOption2() {
        return option2;
    }

    public static class Builder {

        private final Options options = new Options();

        public Builder option1(String option1) {
            this.options.option1 = option1;
            return this;
        }

        public Builder option2(int option2) {
            this.options.option2 = option2;
            return this;
        }

        public Options build() {
            return options;
        }
    }

    private Options() {
    }

    public static void main(String[] args) {
        Options optionsVariation1 = new Options.Builder().option1("firefox").option2(1).build();
        Options optionsVariation2 = new Options.Builder().option1("chrome").option2(2).build();

    }
}

As you can see in my "improved version", there are 2 less places in which we need to add code about any addition properties (or options, in this case)! The only negative that I can see is that the instance variables of the outer class are not able to be final. But, the class is still immutable without this.

Is there really any downside to this improvement in maintainability? There has to be a reason which he repeated the properties within the nested class that I'm not seeing?

1
  • This seems very similar to my take of the builder pattern in C# here.
    – MattDavey
    Commented Nov 9, 2012 at 12:07

3 Answers 3

15

Your variation is quite nice. But it lets users do this:

Options.Builder builder = new Options.Builder().option1("firefox").option2(1);
Options optionsVariation1 = builder.build();
assert optionsVariation1.getOption1().equals("firefox");
builder.option1("chrome");
assert optionsVariation1.getOption1().equals("firefox"); // FAILURE!

Which rather defeats the object.

You could change the build method to do this:

public Options build() {
    Options options = this.options;
    this.options = null;
    return options;
}

Which would prevent this - any call to a setter method on the builder after the build call will fail with a NullPointerException. If you wanted to be flash, you could even test for null and throw an IllegalStateException or something instead. And you could move that up to a generic base class where it could be used across all builders.

1
  • 2
    I would change the 2nd line in build() to: this.options = new Options();. This way, the Options instances would be safely immutable, plus the builder would be reusable at the same time.
    – Natix
    Commented Apr 4, 2013 at 17:51
6

The builder in Bloch's pattern may be used many times to generate objects that are "mostly" the same. Additionally, immutable objects (all fields are final and themselves immutable) have thread safety advantages which your changes may defeat.

0

If Options was effectively cloneable (I mean, regardless of Cloneable interface), you could use prototype pattern - have one in builder and clone it in build().

If you don't use Cloneable interface, you would have to copy every field, so it would add another place where you need to add it, so at least for class with simple fields actualy using Cloneable would be good idea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.