In his book "Effective Java" [1] which I strongly recommend to all Java developers, Bloch introduces the builder pattern as an easy to use method for instantiating objects that require a large number of arguments upon creation.
Note that this builder pattern is not to be confused with the pattern introduced in the infamous Gang of Four book [2].
Typical problems we face when creating objects with aforementioned properties include a myriad of constructors especially when optional arguments come into play as well as possibly illegal intermediate states of the object when resorting to setters. Occasionaly you will also be confronted with a constructor boasting a dozen arguments, the order and meaning of which no one will ever be able to recall.
The builder pattern approaches this problem in the following way: we make the class (and its objects) immutable and uninstantiable. For consumers we provide a builder class. The constructor of the builder class contains all required arguments. Furthermore the builder class contains speaking methods for all optional arguments. Finally it provides a build/generate/create/... method to instantiate the object we want to build.
Consider the following example:
package com.lukaspradel.example;
public class Car {
private final String manufacturer;
private final String model;
private final boolean airConditioning;
private final boolean bikeRack;
private Car(CarBuilder builder) {
this.manufacturer = builder.manufacturer;
this.model = builder.model;
this.airConditioning = builder.airConditioning;
this.bikeRack = builder.bikeRack;
}
public String getManufacturer() {
return manufacturer;
}
public String getModel() {
return model;
}
public boolean isAirConditioning() {
return airConditioning;
}
public boolean isBikeRack() {
return bikeRack;
}
public static class CarBuilder {
private final String manufacturer;
private final String model;
private boolean airConditioning;
private boolean bikeRack;
public CarBuilder(String manufacturer, String model) {
this.manufacturer = manufacturer;
this.model = model;
}
public CarBuilder airConditioning(boolean airConditioning) {
this.airConditioning = airConditioning;
return this;
}
public CarBuilder bikeRack(boolean bikeRack) {
this.bikeRack = bikeRack;
return this;
}
public Car build() {
return new Car(this);
}
}
}
The speaking builder methods are also known as "fluent interfaces"[3].
Building cars is very straight-forward and easy which makes for readable and maintainable code:
public Car getAudiTTLuxury() {
return new CarBuilder("audi", "tt").airConditioning(true)
.bikeRack(false).build();
}
I have two concluding remarks to make. Firstly, when running this code through PMD, e.g. by using SonarQube it will throw two violations:
- (Pointing to method CarBuilder.build()) Avoid instantiation through private constructors from outside of the constructor's class. Instantiation by way of private constructors from outside of the constructor's class often causes the generation of an accessor. A factory method, or non-privitization of the constructor can eliminate this situation. The generated class file is actually an interface. It gives the accessing class the ability to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter. This turns a private constructor effectively into one with package scope, and is challenging to discern.
- (Pointing to the Car class) Class cannot be instantiated and does not provide any static methods or fields. A class that has private constructors and does not have any static methods or fields cannot be used.
This is just PMD being silly and should be ignored in my opinion. There is no point in artificially modifying the above pattern for the sole purpose of satisfying PMD. Consider using the false-positive function of SonarQube.
Secondly, writing the builder methods by hand can be tedious. If you are using Eclipse consider using the Fast Code Plugin [4]. If you are using IntelliJ take a look at the Builder Generator Plugin [5].
1. http://www.oracle.com/technetwork/java/effectivejava-136174.html↩
2. http://c2.com/cgi/wiki?GangOfFour↩
3. http://martinfowler.com/bliki/FluentInterface.html↩
4. http://www.3pintech.com/products/fast-code/↩
5. http://plugins.jetbrains.com/plugin/6585↩