The utility of the Builder Pattern is a clean way to an arbitrary and messy constructor plus enforce immutability of the resulting object. The constructor doesn't have to port enough arguments to support the object's entire configuration, nor choose a subset thereof. And you don't need to shore up what's missing using setters that violate immutability.
The Builder Pattern originated with Joshua Bloch in Effective Java (2nd edition). The GoF (the original "Gang of Four") also have a Builder Pattern, but it's slightly different.
For my preferred example, go to bottom.
Pizza pizza = new Pizza( 12 ); pizza.setCheese( true ); pizza.setPepperoni( true ); pizza.setBacon( true );
Illustration of the Builder pattern:
public class Pizza { private int size; private boolean cheese; private boolean pepperoni; private boolean bacon; public static class Builder { // required private final int size; // optional private boolean cheese = false; private boolean pepperoni = false; private boolean bacon = false; public Builder( int size ) { this.size = size; } public Builder cheese( boolean value ) { cheese = value; return this; } public Builder pepperoni( boolean value ) { pepperoni = value; return this; } public Builder bacon( boolean value ) { bacon = value; return this; } public Pizza build() { return new Pizza( this ); } } private Pizza( Builder builder ) { size = builder.size; cheese = builder.cheese; pepperoni = builder.pepperoni; bacon = builder.bacon; } } Pizza pizza = new Pizza.Builder( 12 ) .cheese( true ) .pepperoni( true ) .bacon( true ) .build();
Telescoping anti-pattern:
Pizza( int size ) { ... } Pizza( int size, boolean cheese ) { ... } Pizza( int size, boolean cheese, boolean pepperoni ) { ... } Pizza( int size, boolean cheese, boolean pepperoni, boolean bacon ) { ... }
Wild-setters anti-pattern:
public class Person { private final String lastName; private final String firstName; private final String middleName; private final String salutation; private final String suffix; private final String streetAddress; private final String city; private final String state; private final boolean isFemale; private final boolean isEmployed; private final boolean isHomewOwner; public Person( final String newLastName, final String newFirstName, final String newMiddleName, final String newSalutation, final String newSuffix, final String newStreetAddress, final String newCity, final String newState, final boolean newIsFemale, final boolean newIsEmployed, final boolean newIsHomeOwner ) { this.lastName = newLastName; this.firstName = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; this.isFemale = newIsFemale; this.isEmployed = newIsEmployed; this.isHomewOwner = newIsHomeOwner; } }
public class PersonBuilder { private String newLastName; private String newFirstName; private String newMiddleName; private String newSalutation; private String newSuffix; private String newStreetAddress; private String newCity; private String newState; private boolean newIsFemale; private boolean newIsEmployed; private boolean newIsHomeOwner; public PersonBuilder() { } public PersonBuilder setNewLastName( String newLastName ) { this.newLastName = newLastName; return this; } public PersonBuilder setNewFirstName( String newFirstName ) { this.newFirstName = newFirstName; return this; } public PersonBuilder setNewMiddleName( String newMiddleName ) { this.newMiddleName = newMiddleName; return this; } public PersonBuilder setNewSalutation( String newSalutation ) { this.newSalutation = newSalutation; return this; } public PersonBuilder setNewSuffix( String newSuffix ) { this.newSuffix = newSuffix; return this; } public PersonBuilder setNewStreetAddress( String newStreetAddress ) { this.newStreetAddress = newStreetAddress; return this; } public PersonBuilder setNewCity( String newCity ) { this.newCity = newCity; return this; } public PersonBuilder setNewState( String newState ) { this.newState = newState; return this; } public PersonBuilder setNewIsFemale( boolean newIsFemale ) { this.newIsFemale = newIsFemale; return this; } public PersonBuilder setNewIsEmployed( boolean newIsEmployed ) { this.newIsEmployed = newIsEmployed; return this; } public PersonBuilder setNewIsHomeOwner( boolean newIsHomeOwner ) { this.newIsHomeOwner = newIsHomeOwner; return this; } public Person createPerson() { return new Person( newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner ); } }
Here's a framework for adding a Builder class to any POJO or other useful class. What it does, using name() and description() won't hold for every situation, but are merely examples. I've done this before (above), but not so elegantly and upon seeing a NiFi example of this (class Relationship), I thought I'd make this note.
publc class Whatever { private String name = ""; private String description = ""; // whatever's implementation... public String getName()... public String getDescription()... public int compareTo( Whatever object )... public boolean equals( Object other )... public int hashCode()... public String toString()... public final class Builder { private String name = ""; private String description = ""; public Builder() { } public Whatever.Builder name( String name ) { if( name != null ) this.name = name; return this; } public Whatever.Builder description( String description ) { if( description != null ) this.description = description; return this; } public Whatever build() { return new Whatever( this ); } } }
This is how Apache NiFi implements PropertyDescriptor. It's how I always do the Builder pattern.
class Cake { private final double sugar; private final double butter; private final int eggs; private final int vanila; private final double flour; private final double bakingpowder; private final double milk; private final int cherry; protected Cake( Builder builder ) { sugar = builder.sugar; butter = builder.butter; eggs = builder.eggs; vanila = builder.vanila; flour = builder.flour; bakingpowder = builder.bakingpowder; milk = builder.milk; cherry = builder.cherry; } public static class Builder { private double sugar; private double butter; private int eggs; private int vanila; private double flour; private double bakingpowder; private double milk; private int cherry; public Builder sugar( double cup ) { this.sugar = cup; return this; } public Builder butter( double cup ) { this.butter = cup; return this; } public Builder eggs( int number ) { this.eggs = number; return this; } public Builder vanila( int spoon ) { this.vanila = spoon; return this; } public Builder flour( double cup ) { this.flour = cup; return this; } public Builder bakingpowder( double spoon ) { this.bakingpowder = spoon; return this; } public Builder milk( double cup ) { this.milk = cup; return this; } public Builder cherry( int number ) { this.cherry = number; return this; } public Cake build() { return new Cake( this ); } } }
Using the above to construct the cake...
public static void main( String args[] ) { Cake whiteCake = new Cake.Builder() .sugar( 1 ) .butter( 0.5 ) .eggs( 2 ) .vanila( 2 ) .flour( 1.5 ) .bakingpowder( 0.75 ) .milk( 0.5 ) .build(); }
This might be a useful copy-and-paste way to get started rather than squinting at the sample above and typing it in. Once you copy and paste, change Clazz, xxxx, yyyy, zzzz, etc.
private final double xxxx; private final int yyyy; private final String zzzz; protected Clazz( Builder builder ) { xxxx = builder.xxxx; yyyy = builder.yyyy; zzzz = builder.zzzz; } public static class Builder { private double xxxx; private double yyyy; private double zzzz; public Builder xXXX( double xxxx ) { this.xxxx = xxxx; return this; } public Builder yYYY( int yyyy ) { this.yyyy = yyyy; return this; } public Builder zZZZ( String zzzz ) { this.zzzz = zzzz; return this; } public Clazz build() { return new Cake( this ); } }