I love pizza and design patterns. This is my first program to practice the builder pattern of GoF, without fluent interface. I put emphasis on the structure and characters of builder pattern.
Here are some notes, hope it will help you read:
Directors --> MeatPizzaLover, CheesePizzaLover. I add an extra-layer of abstraction, PizzaLover, to them.
Builder --> PizzaRecipe.
ConcreteBuilder --> CheesePizzaRecipe, MeatPizzaRecipe.
ComplexProduct --> Oven, Pizza, PrepareTips.
The PrepareTips is the result of a technique called Simple Factory. It's not a pattern but quite useful since it moves the variation part out of its client, the recipes.
There are a lot of points to improve. If you found anything that causes it not a builder pattern of GoF, put emphasis on it, thanks.
Maybe I should make two specific pizza types, CheesePizza and MeatPizza, but sorry, I didn't. I just want to focus on all the main characters in builder pattern. Hope this will not disturb your reading.
Main.java
public class Main {
public static void main(String[] args) throws InterruptedException {
PizzaLover pizzaLover;
Pizza pizza;
pizzaLover = new MeatPizzaLover();
MeatPizzaRecipe meatPizzaRecipe = new MeatPizzaRecipe();
pizzaLover.bakePizza(meatPizzaRecipe);
pizza = meatPizzaRecipe.takeOutPizzaFromOven();
System.out.println(pizza);
pizzaLover = new CheesePizzaLover();
CheesePizzaRecipe cheesePizzaRecipe = new CheesePizzaRecipe();
pizzaLover.bakePizza(cheesePizzaRecipe);
pizza = cheesePizzaRecipe.takeOutPizzaFromOven();
System.out.println(pizza);
}
}
Pizza.java
public class Pizza {
private Size size;
private String bacon;
private String cheese;
private String pepperoni;
private List<String> toppings;
public enum Size { NONE, PERSONAL, STANDARD, FAMILY }
// Omit the default constructor
// Setters & getters.
public void setSize(Size size) {
this.size = size;
}
public void setBacon(String bacon) {
this.bacon = bacon;
}
public void setCheese(String cheese) {
this.cheese = cheese;
}
public void setPepperoni(String pepperoni) {
this.pepperoni = pepperoni;
}
public void setToppings(ArrayList<String> toppings) {
this.toppings = (ArrayList<String>) toppings.clone();
}
public int getSize() {
int inch = 10;
switch (this.size) {
case PERSONAL: inch = 10; break;
case STANDARD: inch = 14; break;
case FAMILY: inch = 16; break;
default:
}
return inch;
}
public String getBacon() {
return this.bacon;
}
public String getCheese() {
return this.cheese;
}
public String getPepperoni() {
return this.pepperoni;
}
public List<String> getToppings() {
return this.toppings;
}
public String toString() {
StringBuilder result = new StringBuilder().append(getSize()).append("-inch pizza with ")
.append(bacon).append(" ")
.append(cheese).append(" ")
.append(pepperoni);
result.append(System.lineSeparator());
for (String topping: this.toppings) {
result.append(" + ").append(topping).append(System.lineSeparator());
}
return result.toString();
}
}
PizzaLover.java
public abstract class PizzaLover {
public abstract void bakePizza(PizzaRecipe pizzaRecipe) throws InterruptedException;
}
CheesePizzaLover.java
public class CheesePizzaLover extends PizzaLover {
@Override
public void bakePizza(PizzaRecipe pizzaRecipe) throws InterruptedException {
System.out.println("In CheesePizzaLover.bakePizza():");
pizzaRecipe.prepareIngredients();
System.out.println("Set oven temperature to 400.0*F");
pizzaRecipe.setOvenTemperature(400.0);
System.out.println("Heat the oven about 2 second...");
pizzaRecipe.setTimeOfOvenTimer(2);
if (pizzaRecipe.getOvenTemperature() < 300.0) {
System.out.println("Since oven temperature less than 300.0*F, re-heat the oven for 2-sec...");
pizzaRecipe.setTimeOfOvenTimer(2);
}
System.out.println("Stretching the pizza dough twice to make it STANDARD size.");
pizzaRecipe.stretchOutDough();
pizzaRecipe.stretchOutDough();
pizzaRecipe.addSauce();
pizzaRecipe.addToppings();
pizzaRecipe.addMeat();
System.out.println("Adding cheese twice.");
pizzaRecipe.addCheese();
pizzaRecipe.addCheese();
pizzaRecipe.putPizzaInOven();
}
}
MeatPizzaLover.java
public class MeatPizzaLover extends PizzaLover {
@Override
public void bakePizza(PizzaRecipe pizzaRecipe) throws InterruptedException {
System.out.println("In MeatPizzaLover.bakePizza():");
pizzaRecipe.prepareIngredients();
System.out.println("Set oven temperature to 300.0*F");
pizzaRecipe.setOvenTemperature(300.0);
System.out.println("Heat the oven about 5 seconds...");
pizzaRecipe.setTimeOfOvenTimer(5);
if (pizzaRecipe.getOvenTemperature() < 500.0) {
System.out.println("Since oven temperature less than 500.0*F, re-heat the oven for 2-sec...");
pizzaRecipe.setTimeOfOvenTimer(2);
}
System.out.println("Stretching the pizza dough three times to make it FAMILY size.");
pizzaRecipe.stretchOutDough();
pizzaRecipe.stretchOutDough();
pizzaRecipe.stretchOutDough();
pizzaRecipe.addSauce();
pizzaRecipe.addToppings();
System.out.println("Adding meat twice.");
pizzaRecipe.addMeat();
pizzaRecipe.addMeat();
pizzaRecipe.addCheese();
pizzaRecipe.putPizzaInOven();
}
}
PizzaRecipe.java
public interface PizzaRecipe {
public void prepareIngredients();
public void setOvenTemperature(double fahrenheit);
public double getOvenTemperature();
public void setTimeOfOvenTimer(int second) throws InterruptedException;
public void stretchOutDough();
public void addSauce();
public void addToppings();
public void addMeat();
public void addCheese();
public void putPizzaInOven() throws InterruptedException;
}
CheesePizzaRecipe.java
public class CheesePizzaRecipe implements PizzaRecipe {
private Pizza pizza = new Pizza();
private PrepareTips prepareTips = new PrepareTips();
private Oven oven = new Oven();
private Pizza.Size currentPizzaSize = Pizza.Size.NONE;
@Override
public void prepareIngredients() {
prepareTips.prepareDoughTips();
}
@Override
public void setOvenTemperature(double fahrenheit) {
oven.setTemperature(fahrenheit);
}
@Override
public double getOvenTemperature() {
return oven.getTemperature();
}
@Override
public void setTimeOfOvenTimer(int second) throws InterruptedException {
oven.setTimer(second);
}
@Override
public void stretchOutDough() {
prepareTips.stretchDoughTips();
switch (currentPizzaSize) {
case PERSONAL: currentPizzaSize = Pizza.Size.STANDARD; break;
case STANDARD: currentPizzaSize = Pizza.Size.FAMILY; break;
case FAMILY: break;
default: currentPizzaSize = Pizza.Size.PERSONAL; break;
}
pizza.setSize(currentPizzaSize);
}
@Override
public void addSauce() {
prepareTips.addSauceTips();
}
@Override
public void addToppings() {
List<String> myToppings = Arrays.asList("Mushrooms", "Onions", "Green peppers", "Pineapple");
pizza.setToppings(new ArrayList<>(myToppings));
}
@Override
public void addMeat() {
pizza.setBacon("Uncured Belly Rashers(bara)");
pizza.setPepperoni("Peppers Pepperoni");
}
@Override
public void addCheese() {
pizza.setCheese("Mozzarella with Extra Cheese: Cheddar, Provolone, Grated Parmesan");
}
@Override
public void putPizzaInOven() throws InterruptedException {
System.out.println("Final 10-sec baking of cheese pizza...");
oven.setTimer(10);
}
public Pizza takeOutPizzaFromOven() {
return pizza;
}
}
MeatPizzaRecipe.java
public class MeatPizzaRecipe implements PizzaRecipe {
private Pizza pizza = new Pizza();
private PrepareTips prepareTips = new PrepareTips();
private Oven oven = new Oven();
private Pizza.Size currentPizzaSize = Pizza.Size.NONE;
@Override
public void prepareIngredients() {
prepareTips.prepareDoughTips();
}
@Override
public void setOvenTemperature(double fahrenheit) {
oven.setTemperature(fahrenheit);
}
@Override
public double getOvenTemperature() {
return oven.getTemperature();
}
@Override
public void setTimeOfOvenTimer(int second) throws InterruptedException {
oven.setTimer(second);
}
@Override
public void stretchOutDough() {
prepareTips.stretchDoughTips();
switch (currentPizzaSize) {
case PERSONAL: currentPizzaSize = Pizza.Size.STANDARD; break;
case STANDARD: currentPizzaSize = Pizza.Size.FAMILY; break;
case FAMILY: break;
default: currentPizzaSize = Pizza.Size.PERSONAL; break;
}
pizza.setSize(currentPizzaSize);
}
@Override
public void addSauce() {
prepareTips.addSauceTips();
}
@Override
public void addToppings() {
List<String> myToppings = Arrays.asList("Mushrooms", "Onions", "Black olives", "Pineapple");
pizza.setToppings(new ArrayList<>(myToppings));
}
@Override
public void addMeat() {
pizza.setBacon("Roasted Peameal Bacon");
pizza.setPepperoni("Garlic Pepperoni");
}
@Override
public void addCheese() {
pizza.setCheese("Mozzarella");
}
@Override
public void putPizzaInOven() throws InterruptedException {
System.out.println("Final 5-sec baking of meat pizza...");
oven.setTimer(5);
}
public Pizza takeOutPizzaFromOven() {
return pizza;
}
}
PrepareTips.java
public class PrepareTips {
public static void appendWithNewLine(StringBuilder stringBuilder, String string) {
stringBuilder.append(string);
stringBuilder.append(System.lineSeparator());
}
public void prepareDoughTips() {
StringBuilder tips = new StringBuilder();
appendWithNewLine(tips, "Taking out the pizza dough from the refrigerator...");
appendWithNewLine(tips, "Covering it and let it warm up to room temperature...");
appendWithNewLine(tips, "Covering the dough keeps the surface from drying out and forming a crust...");
System.out.print(tips.toString());
}
public void stretchDoughTips() {
StringBuilder tips = new StringBuilder();
appendWithNewLine(tips, "Stretching and flattening the dough on a floured work surface...");
System.out.print(tips.toString());
}
public void addSauceTips() {
StringBuilder tips = new StringBuilder();
appendWithNewLine(tips, "Spreading the sauce evenly over the dough...");
System.out.print(tips.toString());
}
}
Oven.java
public class Oven {
private double temperature;
public void setTemperature(double temperature) {
this.temperature = temperature;
}
public double getTemperature() {
return this.temperature;
}
public void setTimer(int sec) throws InterruptedException {
Thread.sleep(sec * 1000);
System.out.println("Ding!");
}
}
Output:
In MeatPizzaLover.bakePizza():
Taking out the pizza dough from the refrigerator...
Covering it and let it warm up to room temperature...
Covering the dough keeps the surface from drying out and forming a crust...
Set oven temperature to 300.0*F
Heat the oven about 5 seconds...
Ding!
Since oven temperature less than 500.0*F, re-heat the oven for 2-sec...
Ding!
Stretching the pizza dough three times to make it FAMILY size.
Stretching and flattening the dough on a floured work surface...
Stretching and flattening the dough on a floured work surface...
Stretching and flattening the dough on a floured work surface...
Spreading the sauce evenly over the dough...
Adding meat twice.
Final 5-sec baking of meat pizza...
Ding!
16-inch pizza with Roasted Peameal Bacon Mozzarella Garlic Pepperoni
+ Mushrooms
+ Onions
+ Black olives
+ Pineapple
In CheesePizzaLover.bakePizza():
Taking out the pizza dough from the refrigerator...
Covering it and let it warm up to room temperature...
Covering the dough keeps the surface from drying out and forming a crust...
Set oven temperature to 400.0*F
Heat the oven about 2 second...
Ding!
Stretching the pizza dough twice to make it STANDARD size.
Stretching and flattening the dough on a floured work surface...
Stretching and flattening the dough on a floured work surface...
Spreading the sauce evenly over the dough...
Adding cheese twice.
Final 10-sec baking of cheese pizza...
Ding!
14-inch pizza with Uncured Belly Rashers(bara) Mozzarella with Extra Cheese: Cheddar, Provolone, Grated Parmesan Peppers Pepperoni
+ Mushrooms
+ Onions
+ Green peppers
+ Pineapple