Thoughts about Builder Pattern
January 10th, 2007 Mario Hochreiter
Recently i watched the recorded presentation "Effective Java Reloaded" from Joshua Bloch which he held at the JavaOne 2006. He stated that static factories and constructors share a problem when they have many optional parameters. For example if you want to construct an ID3Tag object where lets say title and artist are mandatory and album, albumTrack, comment, year, genre etc. are optional one solutions is to write following constructor:
Every time you want to create an ID3Tag object you have to fill in values for all arguments. Typically this ends up that only a small amount of the actual arguments are non "null" values.
Another possible solution is the "Telescoping signature pattern" where you have a constructor with lets say 16 parameters one with 15, 14, 13 and so on. But what if we want to set only the first and 14th parameter. Then you have to take the 14 parameter constructor and fill all parameters except the first with null values.
The "Builder pattern" is a better way to solve this problem. The idea behind the builder pattern is that you write a builder constructor which takes only the mandatory arguments. For ID3Tag this would be title and artist. For all optional parameters there is a corresponding setter in the builder. When you have set all optional parameters you actually build the object from the builder. For our example:
-
ID3Tag u2 = new ID3Tag.Builder("Where the Streets have no name", "U2").album("The Joshua Tree").comment("great song").build();
To make the above code working the following has to be implemented:
-
class ID3Tag {
-
private String title;
-
private String artist;
-
private String album;
-
private int albumTrack;
-
private String comment;
-
-
public static class Builder {
-
private ID3Tag id3tag;
-
-
id3tag = new ID3Tag(title, artist);
-
}
-
-
id3tag.album = val;
-
return this;
-
}
-
-
public Builder albumTrack(int val) {
-
id3tag.albumTrack = val;
-
return this;
-
}
-
-
id3tag.comment = val;
-
return this;
-
}
-
-
// ... a lot more optional parameters
-
-
public ID3Tag build() {
-
return id3tag;
-
}
-
}
-
-
this.title = title;
-
this.artist = artist;
-
}
-
}
The ID3Tag class has its own builder as a static nested class. This gives the builder access to the private fields (via an object reference) of the ID3Tag class. The public builder constructor takes all mandatory parameters and creates a new ID3Tag Object with the private constructor of the ID3Tag class. The ID3Tag object reference is stored in a private field variable.
All optional parameters can be set via setter. The implementation of these setters is straightforward they set the given value for the corresponding field of the ID3Tag class via the ID3Tag reference variable in the builder. Each of these setters returns the builder object itself to allow cascading setting of optional parameters like '.album("The Joshua Tree").comment("great song")...'. Finally the public build method simply returns the stored ID3Tag object reference.
It's that simple as that. I think its a very useful pattern when you have to construct an object with a lot of optional parameters.
Entry Filed under: Patterns
10 Comments Add your own
1. johan chouquet | September 25th, 2007 at 11:31 am
This is a good and simple example.
This pattern is very powerfull, as reality depends a lot on optional elements.
Thanks
2. michael | March 12th, 2008 at 6:44 am
Neat example. I saw the Bloch presentation too and his inner Builder class had member vars that mirrored the outer (product) class while in your example you do it a bit differently in calling the c’tor of the outer class from the Builder c’tor rather than its build() method. Any thoughts on the pros and cons of each approach ? My own idea is that value consistency checks, when required, would be best handled in the build() method, followed by the the creation of the outer class instance in there too.
3. Mario Hochreiter | March 13th, 2008 at 9:34 pm
Hi michael.
You are right that i changed the original version a little bit. The reason is that i just did not want to repeat myself. Meaning that i did not want to have the same members in the outer and inner class as the original version does it.
The pro of this method is that if you add an additional member you do not need to type it twice. Furthermore, i think the members are logically correct belonging to the outer class but are not “correct” members for the builder itself.
The con of this variant is - as you already mentioned - that you cannot do some value consistency checks before constructing the outer object. But that may only be a valid con if the outer object is very expensive to create. In “normal” situations it´s totally o.k. to do the consistency checks in the build method and to throw an Exception for example IllegalArgumentException if some precondition is not met.
Any other con`s you can think of?
4. Impatient | April 21st, 2008 at 10:09 pm
The question in my mind is whether your example preserves Bloch’s priority of keeping the class immutable, and I believe the example is no. Using your code, you could have this situation:
ID3Tag.Builder builder = new ID3Tag.Builder(”Bad”, “U2″).comment(”not bad”);
ID3Tag myTag = builder.build();
builder.comment(”very bad!”);
Here the myTag instance has been changed through builder, whereas in Bloch’s example the builder has separate instance vars and the build() method creates a new instance each time it’s called.
5. Mohan | May 8th, 2008 at 9:55 am
Really nice Example !! Thanks
6. Angelo Schneider | June 29th, 2008 at 5:48 pm
Hm,
this is not the builder pattern. The builder pattern is used to compose a set of objects in a certain way. E.g. create a “document”, place a “title” and add a “paragraph”.
In your example you only create one singel object (not a graph of objects) and you also use one concrete type for this object.
On the first glance your example indeed looks a bit like a builder but what you do there is writing a “fancy contructor”.
A builder would work independent of the concrete object types and usually compose a graph, e.g. a document containing a title and a paragraph. The document and its nested objects then could be instances of HTMLDocumnet, HTMLTitle and HTMLParagraph in one case or RTFDocument, RTFTitle and RTFParagraph in the other case.
Code using the builder would probably look like this:
builder.start(); // get the builder ready to create a new document … alternatively create a new builder
builder.setTitle(”my title”);
builder.addParagraph(”my first paragraph”);
builder.addParagraph(”my second paragraph”);
builder.getDocument(); // construct and _compose_ a document
Usually the point where the builder is used, has no knowledge wether an RTF or an HTML document is “builded”.
Your example always knows and only can create ID3Tags … therefor it is not the builder pattern.
7. Xavi Miró | July 1st, 2008 at 9:36 am
@Impatient,
yes, you’re right, this implementation can’t ensure immutability. You can use duplication of fields as Josh does, or you can complement this implementation throwing exceptions when trying to build more than once the object and when trying to modifiy the object after it’s been built. I prefer doing the latter, because I don’t like duplicating fields. I have complemented this implementation in my blog, here.
Regards,
Xavi
8. Mario Hochreiter | July 1st, 2008 at 1:54 pm
@Angelo Schneider
You are right this is not the “original” builder pattern from the GoF, but a new one presented from Josh Bloch’s at Java One.
Please see also Xavi Miró’s great Blog entry here.
@Xavi Miró
Great idea how to ensure immutability and i appreciate that you like my implementation
9. Beautiful Java « Th&hellip | July 6th, 2008 at 4:39 pm
[…] [Builder pattern with named optional parameters: Effective Java (2nd Edition), Softonaut] Posted by antonis Filed in English, Ελληνικά Tags: Java, […]
10. Xavi Miró | August 1st, 2008 at 8:19 pm
@Mario,
thank you!
I only had to complement your implementation. Although in general I prefer to avoid mutability in compile time, I haven’t found a simple way to do it that didn’t imply duplicating fields, so I chose this runtime check, which is a reasonable balance, in my opinion.
Regards,
Xavi
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed