Builder Pattern Deluxe

July 12, 2007
Update: code available at http://code.google.com/p/garbagecollected/

Yesterday evening I came up with an interesting approach for implementing Josh Bloch's revised GoF Builder pattern (warning: PDF). After some late night hacking, I can't help but feel that this is very useful stuff. Take a look at Josh's presentation first, and then take a look at this:

package builder;

public class SomeObject {
private final String mandatory;
private final int optional1;
private final char optional2;

private SomeObject (SomeObjectBuilder builder, String mandatory) {
this.mandatory = mandatory;
this.optional1 = builder.optional1();
this.optional2 = builder.optional2();
}

public interface SomeObjectBuilder extends Builder {
SomeObjectBuilder optional1(int optional1);
SomeObjectBuilder optional2(char optional2);
int optional1();
char optional2();
}

public static SomeObjectBuilder builder (final String mandatory) {
return BuilderFactory.make (SomeObjectBuilder.class,
new BuilderCallback () {
public SomeObject call (SomeObjectBuilder builder) throws Exception {
return new SomeObject(builder, mandatory);
}
});
}

public String toString() {
return new StringBuilder()
.append (getClass().getName())
.append (String.format ("[optional1=%s, ", optional1))
.append (String.format ("optional2=%s, ", optional2))
.append (String.format ("mandatory=%s]", mandatory)).toString();
}

public static void main(String[] args) {
System.out.println(SomeObject.builder("Mandatory!")
.optional1(35)
.optional2('A')
.build()
.toString()
);
}
}

Console output: SomeObject[optional1=35, optional2=A, mandatory=Mandatory!]

Using a dynamic proxy, the BuilderFactory provides the Builder<T> implementation for a given interface, so that you don't have to write all that horrible boilerplate code. Often you use a builder when constructors get messy, but Builders with many parameters get messy too. Using this approach you not only save time, you also have the advantage of using a static factory method and having your specific builder as an interface instead of a concrete class. Full source code available upon request; feedback/suggestions/improvements appreciated!

Eat that, setter injection ;-)