I tried to implement the builder pattern of GoF. After searching for almost every related posts/examples on the Internet, I'm still confused. But I found that there are two kinds of patterns, which are both called builder:
Bloch Builder : A famous post, but a comment pointed out it's actually a fluent interface, still useful, though. Also notice that it's not the same as Method Chaining, see the differences.
Builder Pattern @thejavageek.com : The author gives a very clear structure of Builder Pattern: Director, Builder, ConcreteBuilder, Product.
Finally I decide to make my own version of "Builder Pattern", which follows the first link above, with some modifications:
- The static method
Pizza.makePizza()
acts as the Director. - For simplicity, I didn't make the
Factory
a factory method or abstract factory, but it can be without problem. - Before you want to make a pizza, you have to override some methods, which you can put anything must be done before the pizza is created.
Main.java
public class Main {
public static void main(String[] args) throws InterruptedException {
Factory myFactory = new Factory();
Pizza myPizza = Pizza.makePizza(new Pizza.Builder(myFactory) {
@Override
public void prepareDough() {
myFactory.prepareDough();
}
@Override
public void prepareToppings() {
myFactory.prepareToppings();
}
}.withSize(20).withBacon().withPepperoni());
System.out.println(myPizza);
}
}
Pizza.java
public class Pizza {
private final int size;
private final boolean cheese;
private final boolean pepperoni;
private final boolean bacon;
private Pizza(Builder builder) {
size = builder.size;
cheese = builder.cheese;
pepperoni = builder.pepperoni;
bacon = builder.bacon;
}
public static Pizza makePizza(Builder builder) throws InterruptedException {
builder.prepareDough();
Thread.sleep(2000);
builder.prepareToppings();
Thread.sleep(2000);
return new Pizza(builder);
}
public static abstract class Builder {
private int size;
private boolean cheese = false;
private boolean pepperoni = false;
private boolean bacon = false;
public Builder(Factory factory) {
}
public Builder withSize(int size) {
this.size = size;
return this;
}
public Builder withCheese() {
cheese = true;
return this;
}
public Builder withPepperoni() {
pepperoni = true;
return this;
}
public Builder withBacon() {
bacon = true;
return this;
}
protected abstract void prepareDough();
protected abstract void prepareToppings();
}
public String toString() {
return String.format("pizza={size=%d, cheese=%s, pepperoni=%s, bacon=%s}",
size,
cheese,
pepperoni,
bacon);
}
}
Factory.java
public class Factory {
public Factory() {}
public void prepareDough() {
System.out.println("Preparing dough...");
}
public void prepareToppings() {
System.out.println("Preparing toppings...");
}
}
Result:
Preparing dough...
Preparing toppings...
pizza={size=20, cheese=false, pepperoni=true, bacon=true}