Monday, 2 December 2013

Builder Design pattern - Implementation [Beverage]

Master Software Architecture & Clean Code!

Subscribe to Ram N Java for clean code, design pattern implementations, and practical Java tutorials!

SUBSCRIBE NOW

Step-by-Step Beverage Construction with Builder Pattern

The Builder Design Pattern is a creational design pattern that solves the issue of complex object instantiation. In beverage preparation, drinks consist of multiple customizable ingredients—water, milk, sugar, and beverage bases like tea or coffee. Using telescoping constructors with multiple arguments makes code error-prone and hard to maintain.

By delegating ingredient configuration to dedicated builder implementations and controlling assembly through a director, the Builder pattern ensures clean, readable, and highly reusable construction workflows.

Complete Java Code Walkthrough

Here is an end-to-end, clean Java implementation demonstrating how to build beverages using the Builder pattern:

// 1. Product Class
class Beverage {
    private int water;
    private int milk;
    private int sugar;
    private String powderType;

    public void setWater(int water) { this.water = water; }
    public void setMilk(int milk) { this.milk = milk; }
    public void setSugar(int sugar) { this.sugar = sugar; }
    public void setPowderType(String powderType) { this.powderType = powderType; }

    @Override
    public String toString() {
        return "Beverage [Water=" + water + "ml, Milk=" + milk + "ml, Sugar=" + sugar + " spoons, Powder=" + powderType + "]";
    }
}

// 2. Builder Interface
interface BeverageBuilder {
    void buildWater();
    void buildMilk();
    void buildSugar();
    void buildPowder();
    Beverage getBeverage();
}

// 3. Concrete Builder: Tea
class TeaBuilder implements BeverageBuilder {
    private Beverage beverage = new Beverage();

    @Override
    public void buildWater() { beverage.setWater(100); }

    @Override
    public void buildMilk() { beverage.setMilk(50); }

    @Override
    public void buildSugar() { beverage.setSugar(2); }

    @Override
    public void buildPowder() { beverage.setPowderType("Tea Leaves"); }

    @Override
    public Beverage getBeverage() { return this.beverage; }
}

// 4. Concrete Builder: Coffee
class CoffeeBuilder implements BeverageBuilder {
    private Beverage beverage = new Beverage();

    @Override
    public void buildWater() { beverage.setWater(60); }

    @Override
    public void buildMilk() { beverage.setMilk(120); }

    @Override
    public void buildSugar() { beverage.setSugar(1); }

    @Override
    public void buildPowder() { beverage.setPowderType("Filter Coffee Powder"); }

    @Override
    public Beverage getBeverage() { return this.beverage; }
}

// 5. Director Class
class BeverageDirector {
    private BeverageBuilder builder;

    public BeverageDirector(BeverageBuilder builder) {
        this.builder = builder;
    }

    public void constructBeverage() {
        builder.buildWater();
        builder.buildMilk();
        builder.buildSugar();
        builder.buildPowder();
    }

    public Beverage getBeverage() {
        return builder.getBeverage();
    }
}

// 6. Client Application
public class BeverageBuilderApp {
    public static void main(String[] args) {
        // Construct Tea
        BeverageBuilder teaBuilder = new TeaBuilder();
        BeverageDirector teaDirector = new BeverageDirector(teaBuilder);
        teaDirector.constructBeverage();
        Beverage tea = teaDirector.getBeverage();
        System.out.println("Serving: " + tea);

        // Construct Coffee
        BeverageBuilder coffeeBuilder = new CoffeeBuilder();
        BeverageDirector coffeeDirector = new BeverageDirector(coffeeBuilder);
        coffeeDirector.constructBeverage();
        Beverage coffee = coffeeDirector.getBeverage();
        System.out.println("Serving: " + coffee);
    }
}

Key Architectural Benefits

  • Encapsulated Construction: Isolates the step-by-step beverage assembly logic away from the client application.
  • Flexible Variations: Enables creating distinct beverages (tea, coffee, or hot chocolate) with the exact same construction sequence.
  • Cleaner Codebase: Eliminates large, confusing constructor parameter lists and avoids partial or inconsistent object states.

Watch More Related Design Pattern Tutorials


Click here to watch in Youtube : https://www.youtube.com/watch?v=enDdOjXr1GI

Click the below Image to Enlarge
Builder Design pattern - Implementation [Beverage]
Builder Design pattern - Implementation [Beverage] - Class Diagram













































Beverage.java

public class Beverage
{

private int    water;
private int    milk;
private int    sugar;
private int    powderQuantity;
private String beverageName;

public int getWater()
{
return water;
}

public void setWater( int water )
{
this.water = water;
}

public int getMilk()
{
return milk;
}

public void setMilk( int milk )
{
this.milk = milk;
}

public int getSugar()
{
return sugar;
}

public void setSugar( int sugar )
{
this.sugar = sugar;
}

public int getPowderQuantity()
{
return powderQuantity;
}

public void setPowderQuantity( int powderQuantity )
{
this.powderQuantity = powderQuantity;
}

public String getBeverageName()
{
return beverageName;
}

public void setBeverageName( String beverageName )
{
this.beverageName = beverageName;
}

public String toString()
{
return "Hot " + beverageName + "!!!!  [" + water + " ml of water, " + milk + "ml of milk, " + sugar
               + " gm of sugar, " + powderQuantity + " gm of " + beverageName + "]\n";
}

}

BeverageBuilder.java

/**
 * 
 * BeverageBuilder is a blue print for any Class that wants to create
 * Beverage. It will have different subClass implementations of BeverageBuilder
 * for different beverages[e.g. coffee,tea,Horlicks etc].
 */
public abstract class BeverageBuilder
{

private Beverage beverage;

public Beverage getBeverage()
{
return beverage;
}

public void setBeverage( Beverage beverage )
{
this.beverage = beverage;
}

/*
* Template method that creates Beverage Object and returns Beverage
* Object after adding components in required proportion.
*/
public final Beverage buildBeverage()
{
Beverage beverage = createBeverage();
setBeverage(beverage);
setBeverageType();
setWater();
setMilk();
setSugar();
setPowderQuantity();
return beverage;
}

abstract void setBeverageType();

abstract void setWater();

abstract void setMilk();

abstract void setSugar();

abstract void setPowderQuantity();

abstract Beverage createBeverage();

}


CoffeeBuilder.java

/* 
 * CoffeeBuilder creates coffee by mixing the components[water,milk,sugar,coffee powder]. 
 * CoffeeBuilder implements BeverageBuilder which is bluePrint for creating beverage objects.
 * */
public class CoffeeBuilder extends BeverageBuilder
{
Beverage createBeverage()
{
return new Beverage();
}

public void setWater()
{
System.out.println("Step 1 : Boiling water");
getBeverage().setWater(40);
}

public void setMilk()
{
System.out.println("Step 2 : Adding milk");
getBeverage().setMilk(50);
}

void setSugar()
{
System.out.println("Step 3 : Adding sugar");
getBeverage().setSugar(10);
}

void setPowderQuantity()
{
System.out.println("Step 4 : Adding 9 Grams of coffee powder");
getBeverage().setPowderQuantity(9);
}

void setBeverageType()
{
System.out.println("Coffee");
getBeverage().setBeverageName("Coffee");
}

}

TeaBuider.java

/* 
 * TeaBuilder creates Tea by mixing the components[water,milk,sugar,tea powder]. 
 * It implements BeverageBuilder which is bluePrint for creating beverage objects.
 * */
public class TeaBuider extends BeverageBuilder
{

Beverage createBeverage()
{
return new Beverage();
}

public void setWater()
{
System.out.println("Step 1 : Boiling water");
getBeverage().setWater(40);
}

public void setMilk()
{
System.out.println("Step 2 : Adding milk");
getBeverage().setMilk(50);
}

void setSugar()
{
System.out.println("Step 3 : Adding sugar");
getBeverage().setSugar(10);
}

void setPowderQuantity()
{
System.out.println("Step 4 : Adding 9 Grams of tea powder");
getBeverage().setPowderQuantity(9);
}


void setBeverageType()
{
System.out.println("Tea");
getBeverage().setBeverageName("Tea");
}

}


HotelWaiter.java

public class HotelWaiter
{

public static Beverage takeOrder( String beverageType )
{

BeverageBuilder beverageBuilder = null;

if( beverageType.equalsIgnoreCase("tea") )
{
beverageBuilder = new TeaBuider();
}
else if( beverageType.equalsIgnoreCase("coffee") )
{
beverageBuilder = new CoffeeBuilder();
}
else
{
System.out.println("Sorry we don't take order for  " + beverageType);
}
return beverageBuilder.buildBeverage();
}

}


BuilderClient.java

/*
 *  Customer who is in hotel and customer can place order to 
 *  HotelWaiter or Servant.
 */
public class BuilderClient
{
public static void main( String[] args )
{

Beverage tea = HotelWaiter.takeOrder("tea");
System.out.println(tea);
Beverage coffee = HotelWaiter.takeOrder("coffee");
System.out.println(coffee);
}
}


Output

Tea
Step 1 : Boiling water
Step 2 : Adding milk
Step 3 : Adding sugar
Step 4 : Adding 9 Grams of tea powder
Hot Tea!!!!  [40 ml of water, 50ml of milk, 10 gm of sugar, 9 gm of Tea]

Coffee
Step 1 : Boiling water
Step 2 : Adding milk
Step 3 : Adding sugar
Step 4 : Adding 9 Grams of coffee powder
Hot Coffee!!!!  [40 ml of water, 50ml of milk, 10 gm of sugar, 9 gm of Coffee]

See also:

  • Builder Design Pattern - Introduction
  • Builder Design pattern - Real Time Example [Meal Package]
  • Builder Design pattern - Real Time Example [Animal Toys]
  • Builder Design pattern - Real Time Example [Beverage]
  • Builder Design Pattern - Class Diagram
  • Builder Design Pattern - Sequence Diagram
  • Builder Design Pattern - Implementation [Animal Toy]
  • Builder Design Pattern - KeyPoints
  • All Design Patterns Links
  • Tutorials