Saturday, July 11, 2009

Introducing the Builder Design Pattern

Static factories and constructors have limitations when dealing with objects with large numbers of optional parameters.

A classic solution is to use multiple constructors. The first constructor will have only the required parameters. The second one, the required parameters and a single optional parameter. The third one, the required parameters and two optional parameter and so one until the last optional parameter. The problem with this solution is that you can easily invert two parameters when constructing the object.

Another solution is to use the JavaBean pattern, in which you call the paramterless constructor and call the setter methods to populate your objects. The problem with this pattern is that you cannot enforce consistency. Your objects may be in an inconsistent state if you do not set the required parameters.

A third solution is to use the builder design pattern.

Here's an interesting implementation of this design pattern described by Joshua Bloch in the book 'Effective Java Second Edition' (which is, by the way, a book to put in every programmer hands).

The client calls a constructor with all the required parameters and gets a builder object. Then the client calls methods on the builder object to set each optional parameters. Finally the client calls a build method which generate an instance of the object which is immutable. Immutable objects have a lots of benefits and may be very useful.

public class Customer {

private final String name;
private final String surname;
private final int age;
private final String address;
private final String email;

public static class Builder {

//Mandatory parameters
private String name;
private String surname;

//Optional parameters
private int age;
private String address;
private String email;

public Builder(String name, String surname) {
this.name = name;
this.surname = surname;
}

public Builder age(int val) {
age = val;
return this;
}

public Builder address(String val) {
address = val;
return this;
}

public Builder email(String val) {
email = val;
return this;
}

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

private Customer(Builder builder) {
name = builder.name;
surname = builder.surname;
age = builder.age;
address = builder.address;
email = builder.email;
}
}

A good practice is to check the invariants in the build method and send an IllegalStateException if one of the attribute is invalid. This way, you will always be sure that your object is valid after being instantiated.

Here's how the client code looks :

Customer customer = new Customer.Builder("John", "Doe").age(25).email("johndoe@gmail.com").build();

The result is a client code easy to write and read.

Resources : To mutate or not to mutate ?

7 comments:

Andy said...

But you will have to type a lot of duplicated parameters...does IDE have the Design Pattern generator for this?

Dave Newton said...

Why not just put the fluent methods in the Customer class?

ferdhie said...

what is wrong with old plain constructor?

shifteleven said...

The problem with a plain old constructor is that if you have too many parameters to fill, it becomes very unreadable as what parameter is what.

The reason I understand to use the Builder patterns is when you need to create a bean and you need to synchronize all of your parameters at once or do something else critical with the properties. As mentioned, you need the state of the bean to be consistent.

If it doesn't have to maintain this consistency, I also like to throw in this option:

Customer customer = new Customer("John", "Doe") {
setAge(25)
setEmail("johndoe@gmail.com");
};

I love the interface of the Builder pattern, I just hate the extra boilerplate code.

Alexander.A said...

iy's not a builder pattern. it's a java code.

Julien Dechmann said...

I don't like boilerplate code too. If you have simple objects keep it simple. The main advantage of this pattern is to create immutable objects which can be very handy in multi-threaded environment.

Julien Dechmann said...

And checking the invariants in the build method will ensure the validity of your objects.

Post a Comment