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 ;-)

4 Responses to “Builder Pattern Deluxe”

  1. Greg Roaner Says:

    Came across your website. I happened to be looking at the Builder pattern and I would like to see your source code, especially for BuilderFactory and BuilderCallback.

  2. bmthykm Says:

    This implementation won’t with constructors that take an interface as a constructorArg, right? Since you use constructor.getClass() in the BuilderFactory, you’ll get the runtime class. When constructor.newInstance() is called, the types won’t match.

    Example:
    private SomeClass(SomeClassBuilder, List list)

    // caller code
    SomeClass.builder(new ArrayList ()).build()

    The BuilderFactory will newInstance() with a constructor of types(SomeClassBuilder, ArrayList) and a MethodNotFoundException will be thrown.


Leave a Reply