The builder pattern is a design pattern that allows for the step-by-step creation of complex objects using the correct sequence of actions.
The construction is controlled by a director object that only needs to know the type of object it is to create.
1. Motivation
The more complex an application is, the complexity of classes and objects used increases.
Complex objects are made of parts produced by other objects that need special care when being built.
An application might need a mechanism for building complex objects that is independent from the ones that make up the object.
The pattern allows a client object to construct a complex object by specifying only its type and content, being shielded from the details related to the object's representation.
The way the construction process can be used to create different representations.
The logic of this process is isolated from the actual steps used in creating the complex object,
so the process can be used again to create a different object from the same set of simple objects as the first one.
2. Intent
1> Defines an instance for creating an object but letting subclasses decide which class to instantiate.
2> Refers to the newly created object through a common interface.
3. Example
1> Simple Example
package edu.xmu.oop.builder;
public class Person {
private final String lastName; // required
private final String firstName; // required
private final String middleName; // optional
private final String salutation;// optional
private final String suffix;// optional
private final String streetAddress;// optional
private final String city;// optional
private final String state;// optional
private final boolean isEmployed;// optional
private final boolean isFemale;// required
private final boolean isHomewOwner;// optional
private Person(Builder personBuilder) {
this.lastName = personBuilder.lastName;
this.firstName = personBuilder.firstName;
this.middleName = personBuilder.middleName;
this.salutation = personBuilder.salutation;
this.suffix = personBuilder.suffix;
this.streetAddress = personBuilder.streetAddress;
this.city = personBuilder.city;
this.state = personBuilder.state;
this.isEmployed = personBuilder.isEmployed;
this.isFemale = personBuilder.isFemale;
this.isHomewOwner = personBuilder.isHomewOwner;
}
public static class Builder {
private final String lastName; // required
private final String firstName; // required
private String middleName = ""; // optional
private String salutation = "";// optional
private String suffix = "";// optional
private String streetAddress = "";// optional
private String city = "";// optional
private String state = "";// optional
private final boolean isFemale;// required
private boolean isEmployed = false;// optional
private boolean isHomewOwner = false;// optional
public Builder(String lastName, String firstName, boolean isFemale) {
super();
this.lastName = lastName;
this.firstName = firstName;
this.isFemale = isFemale;
}
public Builder setMiddleName(String middleName) {
this.middleName = middleName;
return this;
}
public Builder setSalutation(String salutation) {
this.salutation = salutation;
return this;
}
public Builder setSuffix(String suffix) {
this.suffix = suffix;
return this;
}
public Builder setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
return this;
}
public Builder setCity(String city) {
this.city = city;
return this;
}
public Builder setState(String state) {
this.state = state;
return this;
}
public Builder setEmployed(boolean isEmployed) {
this.isEmployed = isEmployed;
return this;
}
public Builder setHomewOwner(boolean isHomewOwner) {
this.isHomewOwner = isHomewOwner;
return this;
}
public Person build() {
return new Person(this);
}
}
@Override
public String toString() {
return "Person [lastName=" + lastName + ", firstName=" + firstName
+ ", middleName=" + middleName + ", salutation=" + salutation
+ ", suffix=" + suffix + ", streetAddress=" + streetAddress
+ ", city=" + city + ", state=" + state + ", isEmployed="
+ isEmployed + ", isFemale=" + isFemale + ", isHomewOwner="
+ isHomewOwner + "]";
}
}
package edu.xmu.oop.builder;
import org.apache.log4j.Logger;
import org.junit.Test;
public class PersonTest {
private static final Logger logger = Logger.getLogger(PersonTest.class);
@Test
public void buildTest() {
Person p = new Person.Builder("Yang", "Kunlun", false)
.setCity("Shanghai").setEmployed(true)
.setStreetAddress("Chenhui RD").build();
logger.info(p);
}
}
Attention: 1> Person.Build has to be public static for outter class to have access to this Builder class
2> Person.Build has to have the same attributes as Person have and have to unfinalize the optional attributes.
3> Person's constructor has to be private in that outter class cannot construct Person directly.
2> Guava Example
package edu.xmu.oop.builder;
public class ImmutableList {
private final transient Object[] array;
private ImmutableList(Object[] array) {
this.array = array;
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
static final int DEFAULT_INITIAL_CAPACITY = 4;
Object[] contents;
int size;
public Builder() {
this(DEFAULT_INITIAL_CAPACITY);
}
Builder(int initialCapacity) {
this.contents = new Object[initialCapacity];
this.size = 0;
}
public Builder add(E element) {
ensureCapacity(size + 1);
contents[size++] = element;
return this;
}
private void ensureCapacity(int minCapacity) {
// ...
}
@SuppressWarnings("unchecked")
public ImmutableList build() {
switch (size) {
case 0:
return (ImmutableList) new ImmutableList