Builder Design Pattern Applied

Hi there!

Today i’m gonna share the first of a brand new design pattern series i made. The builder design pattern is a very useful and common pattern while developing serious apps. In this post i’ll give a tiny builder pattern framework, so you can always come back here and get it to work with.

A mnemonic, while dealing with builder pattern, is to think about customization. I always think about it, when i’m figuring out if i should use it or if i better take a factory. That’s the way it works better for me. try yourself.
 

The UML

Here is how the little framework looks like. Simple, nice and straightforward.

builder

The code behind it

The code is also very simple, small, clean and self-explanatory. I like to code expressive, so i don’t need to comment a lot. In this sample here i did, because it has a tutorial character. While developing i created some convention to my self. I think it is very important to do so. It is like applying the right grammar on a language while developing.

For example: If i’m using the Builder Pattern, i always put the suffix Builder at the end. Well you may say or think now: what? But thats in fact a very, very, important info for beginners and expirienced developers. They will automatically see the idea behind it and will try not to break the pattern. In fact expirienced developers will love it and try to continue a good work, because they know, that the developer who wrote this, knows what he did and for sure there was a reason for it.

So always try to be clear enough and give the right information on the right places. Someone else will thank you later.  But now to the code…

// 1. EXAMPLE: PARTS OF THE CUSTOMIZABLE PRODUCT WE WANT
public interface Part {
    // DEFINE THE METHODS YOUR PARTS WILL HAVE...
    void anyMethodNameYouLike();
}

// 2. THE BUILDER METHOD WILL ADD 
// PARTS RETURNING THE BUILDER ITSELF
public interface BuildContract < B > {
    B mount(Part part);
}

// 3. DEFINE THE BUILDER'S CONTRUCTION METHOD
// WHICH BUILDS AND RETURNS THE FINAL PRODUCT "T"
public interface Builder < T > extends BuildContract < Builder < T > > {
    T build();
}

A real example

Nothing better then that to fix it and understand it better. Let´s implement a cake bakery. A colleague of yours wants to open a bakery and asked you to program a bakery’s software for him. Let’s do it..!

And by the way, I commend you heartily, using a UML diagram tool is as visualization mechanism to show your ideas and improve your design skills. Lets start by the UML:

builder_en

The analogy

Let’s now use our tiny framework and make the analogy for our bakery. Ingredient is the Part, Recipe is the BuilderContract and  Builder is the builder itself. Cake is the final, customizable product. CakeBuilder is the class which actually creates the product after customization (after the addition of as many parts – ingredients – as you want). The client would be the final client or your colleague taking the order. Just use or imagination… Let’s dive into code now…

The Ingredients (Parts)

The parts in our example are the ingredients. Let’s implement some ingredients to use it later to make a cake.

// 1. EXAMPLE: PART TO CUSTOMIZATE "INGREDIENTS"
public interface Ingredient {
    // INGREDIENTS WILL HAVE...
    void printName();
    String getUnitPrice();
    void printCalories();
}
public class LightMilk implements Ingredient {

    private int deciLiter;
    private int calories;
    private String unitPrice;
    
    public LightMilk(int deciLiter){this.deciLiter=deciLiter;}
    
    public LightMilk(int deciLiter, int calories, String unitPrice) {
        super();
        this.deciLiter = deciLiter;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" Light Milk");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 76kc");}
    public int getDeciLiter() {return deciLiter;}
    public void setDeciLiter(int deciLiter) {this.deciLiter = deciLiter;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}
public class Sugar implements Ingredient {

    private int gram;
    private int calories;
    private String unitPrice;
    
    public Sugar(int deciLiter){this.gram=deciLiter;}
    
    public Sugar(int gram, int calories, String unitPrice) {
        super();
        this.gram = gram;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" Sugar");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 40kc");}
    public int getGram() {return gram;}
    public void setGram(int gram) {this.gram = gram;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}
public class Choco implements Ingredient {
    private int gram;
    private int calories;
    private String unitPrice;
    public Choco(int gram, int calories, String unitPrice) {
        super();
        this.gram = gram;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }
    public int getGram() {return gram;}
    public void setGram(int gram) {this.gram = gram;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}

    @Override public void printName() {System.out.printf(" Chocolate");}
    @Override public void printCalories() {System.out.printf(" 389kc");}
    @Override public String getUnitPrice() {return unitPrice;}
}
public class NoSugar implements Ingredient {

    private int gram;
    private int calories;
    private String unitPrice;
    
    public NoSugar(int deciLiter){this.gram=deciLiter;}
    
    public NoSugar(int gram, int calories, String unitPrice) {
        super();
        this.gram = gram;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" No Sugar");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 0kc");}
    public int getGram() {return gram;}
    public void setGram(int gram) {this.gram = gram;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}
public class Milk implements Ingredient {

    private int deciLiter;
    private int calories;
    private String unitPrice;
    
    public Milk(int deciLiter){this.deciLiter=deciLiter;}
    
    public Milk(int deciLiter, int calories, String unitPrice) {
        super();
        this.deciLiter = deciLiter;
        this.calories = calories;
        this.unitPrice = unitPrice;
    }

    @Override public void printName() {System.out.printf(" Milk");}
    @Override public String getUnitPrice() {return unitPrice;}
    @Override public void printCalories() {System.out.printf(" 128kc");}
    public int getDeciLiter() {return deciLiter;}
    public void setDeciLiter(int deciLiter) {this.deciLiter = deciLiter;}
    public int getCalories() {return calories;}
    public void setCalories(int calories) {this.calories = calories;}
    public void setUnitPrice(String unitPrice) {this.unitPrice = unitPrice;}
}

The Builder’s Contract

This is the Recipe in our example.

// 2. THE BUILDER METHOD WILL ADD 
// INGREDIENTS RETURNING THE BUILDER ITSELF
public interface Recipe < B > {
    B addIngredient(Ingredient ingredient);
}
// 3. DEFINE THE BUILDER CONTRUCTION METHOD
// WHICH BUILDS AND RETURNS THE FINAL PRODUCT "T"
public interface Builder < T > extends Recipe < Builder < T > > {
    T build();
}
import java.util.ArrayList;
import java.util.List;
// 4. IMPLEMENT THE BUILDER ACC. TO YOUR NEEDS
public class CakeBuilder implements Builder < Cake > {
    // IN THIS CASE THE PARTS ARE THE INGREDIENTS
    private List < Ingredient > ingredients=new ArrayList < Ingredient > ( );
    @Override
    public Cake build() {
        if(!ingredients.isEmpty()){
            // THE FINAL PRODUCT IS A CHOCO-MUFFIN
            return new Cake(ingredients);
        }
        return new Cake(null);
    }
    @Override
    // BECAUSE I ALWAYS GET A BUILDER BACK, I'M ABLE TO
    // ADD A LOT OF PARTS BEFORE I CALL "BUILD()"
    public Builder < Cake > addIngredient(Ingredient ingredient) {
        if(ingredient!=null){
            ingredients.add(ingredient);
        }
        return this;
    }
}

The product

In our example the product to build is a cake.

import java.util.List;

public class Cake {
    public Cake(List < Ingredient > ingredients){
        String muffin = "";
        if(ingredients==null){
            System.out.println(" zero cake "+muffin);
            return;
        }
        // PRINT OUT MUFFIN INGREDIENTS
        System.out.printf(" Cake with: ");
        for (Ingredient ingredient : ingredients) {
            ingredient.printName();
        }
        // PRINT OUT PART PRICES
        for (Ingredient ingredient : ingredients) {
            muffin+=" "+ingredient.getUnitPrice();//NOPMD
        }
        System.out.println(" - Price: "+muffin);
    }
    public void printResult(){
        System.out.println(" Cake is ready!");
    }
}

Testing it

Finally the client test. Here we can see the usage of it:

// 5. TESTING THE CHOCO-BUILDER
public class Client {
    public static void main(String[] args) {
        Builder < Cake > chocoMuffinBuilder = new CakeBuilder();
        chocoMuffinBuilder.addIngredient(new Choco(10, 23, "3.39"));
        chocoMuffinBuilder.addIngredient(new Milk(34, 67, "1.57"));
        chocoMuffinBuilder.addIngredient(new Sugar(34, 67, "2.00"));
        final Cake chocoMuffin = chocoMuffinBuilder.build();
        chocoMuffin.printResult();
    }
}

That’s all! Hope you like it!

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

One Response to "Builder Design Pattern Applied"

  1. Hi Ricardo,

    I really liked your implementation of Builder pattern. It seems, in terms of implementation, there could be multiple variations of same patterns, or we may say multiple flavours (the word “flavours” suits more considering your CakeBuilder :) ). But i am not sure about your basic idea of builder, you see builder pattern as a Customizable or Assembled unit, which you have very well implemented. Where as i see builder pattern as a template based development of a complex product (object). In concrete terms the Recipe object in your CakeBuilder example must hold the steps for cake development like step 1 : Make Dough Step 2: Bake Step 3: Add Icing to the cacke. 4. Add Birthday Message with Cream. The Builder’s build method must utilize the recipe for creating a cake, Now in order to have different type of cakes all we need to do is add new recipes, in other words implement Recipe interface for creating different types of recipes. In your code the responsibility of implementation of recipe i.e. addIngredient lies with the builder itself rather that creation of a recipe object. What if we require more than one recipes?

    My thinking could be wrong but this is how i have been using builder pattern.

Leave a Reply


four × = 12



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close