Design Pattern: Builder Pattern

Summary

Pattern NameBuilder Pattern
Pattern TypeCreational Pattern
Scope Object
TaglineSeparate construction of a complex object from representation
Use cases1. When we want to use the same construction process
to create a different representation.
2. When we want to build an object step-by-step.
Related PatternsAbstract Factory
Composite
Difficulty LevelMedium
Implementations

Definition

Builder Pattern comes into play when we need to construct a complex object. Builder Pattern will hide the complexity of the object construction from the user. Builder Pattern will allow the complex object to be built step-by-step.

When there are lots of parameters for object construction and some of those are (may or may not be) optional, then it’s difficult to set those parameters in the constructor. In that case, we can use Builder pattern, as that will allow the param to be set step by step and also we can ignore the optional parameters.

By separating the construction(building) of the object from the actual class, we can make the actual concrete object immutable. As setting the params & building the object part is handled in the builder class and the concrete class does not have any method to change object properties directly. That way Builder gives us more control over the object construction.

Use Cases

Here are the use cases of Builder pattern –

  • When we want to abstract the complex creation process of an object. And want to separate the creation & usage/presentation of an object.
  • When there are lots of arguments/params, they need to be passed to the class. It is not ideal to pass it through the constructor or any other method. Builder pattern can be used here so that the builder can accept the parameter setup-by-step.
  • When there are lots of parameters and maintaining the order of param is difficult.
  • When there are optional parameters and keeping track of those parameters is difficult.
  • When the object is complex and other patterns(like Factory Pattern) can not handle it well.
  • When we want to share and reuse the complex object creation process for multiple objects.

Implementation

Builder pattern implementation has 4 elements.

  1. Concrete Class: Main item classes. Generating object of these classes is the goal of the builder pattern.
  2. Builder: interface to create some parts of the concrete class objects.
  3. Concrete Builder Class: Implementation of the builder interface. These builder classes are responsible for building the concrete classes.
  4. Producer: Uses the concrete builder classes and produces the final result object. This is also called Director.

While implementing Builder pattern, the Producer can be skipped. We can write the building part to the client directly, if we prefer.

In the following implementation diagram, we are skipping the producer, for simplicity.

Here are the steps to follow for implementing Builder pattern:

  1. Define concrete classes for items. Add only getter functions, no need to implement any setter.
  2. Create an interface for the builder.
  3. Create builder concrete classes and implement the builder interface.
  4. In the builder class, add functions to set the values.
  5. In builder add a function to generate an object of the concrete item class and return it.
  6. Create a producer class and add a function to return the builder object.
  7. In the client, pass a builder object to the producer. Use the builder object returned by the producer.

Examples

Here are a few examples of Builder pattern implementation. All these implementations use Pseudocode. For language-specific implementation check the Code Implementations section.

Example #1: Vehicle Builder

Let’s take the example of a transport system. Take a look at the implementation.

Concrete Classes for Items

  • Declare classes that we want to build objects for. Here we have classes for cars and planes.
  • In the constructor receive the params required for building the object.
// Car class

class Car
    var wheel: int
    var engine: int
    var seat: int
    var door: int
    var interior: boolean

    // Define constructor
    constructor(noOfWheelParam: int, noOfEngineParam: int, noOfSeatParam: int, noOfDoorParam: int, interiorParam: boolean)
       wheel = noOfWheelParam
       engine = noOfEngineParam
       seat = noOfSeatParam
       door = noOfDoorParam
       interior = interiorParam
    end constructor

    function getWheel(): int
        return wheel
    end function

    function getEngine(): int
        return engine
    end function

    function getSeat(): int
        return seat
    end function

    function getDoor(): int
        return door
    end function

    function isInterior(): boolean
        return interior
    end function

    function toString(): String
        return "Car: Wheel -> " + wheel + " | Engine -> " + engine + " | Seat -> " + seat + " | Door -> " + door + " | Interior -> " + interior
    end function

end class


// Plane class

class Plane
    var wheel: int
    var engine: int
    var seat: int
    var door: int
    var wing: int
    var interior: boolean
    
    // Define constructor
    constructor(noOfWheelParam: int, noOfEngineParam: int, noOfSeatParam: int, noOfDoorParam: int, wingParam: int, interiorParam: int)
       wheel = noOfWheelParam
       engine = noOfEngineParam
       seat = noOfSeatParam
       door = noOfDoorParam
       wing = wingParam
       interior = interiorParam
    end constructor

    function getWheel(): int
        return wheel
    end function

    function getEngine(): int
        return engine
    end function

    function getSeat(): int
        return seat
    end function

    function getDoor(): int
        return door
    end function

    function getWing(): int
        return wing
    end function

    function isInterior(): int
        return interior
    end function

    function toString(): String
        return "Plane: Wheel -> " + wheel + " | Engine -> " + engine + " | Seat -> " + seat + " | Door -> " + door + " | Wing: " + wing + " | Interior -> " + interior
    end function

end class

Builder Interface and Builder classes

  • Create “VehicleBuilder” interface, to ensure a common interface for the builder classes. In the interface declare methods so that we can set values of the classes.
  • Create builder classes, like, “CarBuilder” for building the “Car” class object and “PlaneBuilder” for building the “Plane” class object.
  • In the builder class define a method named “build()”. And in the build method create a new object of relevant class (car or plane).
// Builder Interface

interface VehicleBuilder

   addWheel(noOfWheelParam: int)

   addEngine(noOfEngineParam: int)

   addSeat(noOfSeatParam: int)

   addInterior()

   addDoor(noOfDoorParam: int)

   addWing(noOfWingParam: int) throws Exception

end interface


// Car Builder Class

class CarBuilder implements VehicleBuilder
    var wheel: int
    var engine: int
    var seat: int
    var door: int
    var interior: boolean

    function addWheel(noOfWheelParam: int)
        print("Add " + noOfWheelParam + " wheels")

       wheel += noOfWheelParam
    end function

    function addEngine(noOfEngineParam: int)
        print("Add " + noOfEngineParam + " engine")

       engine += noOfEngineParam
    end function

    function addSeat(noOfSeatParam: int)
        print("Add " + noOfSeatParam + " Seat")

       seat = noOfSeatParam
    end function

    function addInterior()
        print("Add interior")

       interior = true
    end function

    function addDoor(noOfDoor: int)
        print("Add " + noOfDoor + " door")

       door += noOfDoor
    end function

    function addWing(noOfWing: int) throws Exception
        throw new Exception("Can not add wings")
    end function

    function build(): Car
        Car car = new Car(wheel, engine, seat, door, interior)

        return car
    end function

end class

// Plane Builder Class

class PlaneBuilder implements VehicleBuilder
    var wheel: int
    var engine: int
    var seat: int
    var door: int
    var wing: int
    var interior: boolean

    function addWheel(noOfWheelParam: int)
        print("Add " + noOfWheel + " wheels")

       wheel += noOfWheel
    end function

    function addEngine(noOfEngineParam: int)
        print("Add " + noOfEngineParam + " engine")

       engine += noOfEngineParam
    end function

    function addSeat(noOfSeatParam: int)
        print("Add " + noOfSeatParam + " Seat")

       seat = noOfSeatParam
    end function

    function addInterior()
        print("Add interior")

       interior = true
    end function

    function addDoor(noOfDoorParam: int)
        print("Add " + noOfDoorParam + " door")

       door += noOfDoorParam
    end function

    function addWing(noOfWingParam: int) throws Exception
        print("Add " + noOfWingParam + " wing")

       wing += noOfWingParam
    end function

    function build(): Plane
        Plane plane = new Plane(wheel, engine, seat, door, wing, interior)

        return plane
    end function

end class

Producer

  • Create “VehicleProducer” class and define methods for building car and plane.
  • Define method for building object. This method accepts a builder object and set value

We can ignore the producer and create the object directly where we want to create the objects.


// Producer class

class VehicleProducer
   function buildCar(CarBuilder carBuilder): CarBuilder
        carBuilder.addWheel(4)
        carBuilder.addEngine(1)
        carBuilder.addDoor(4)
        carBuilder.addSeat(4)
        carBuilder.addInterior()

        return carBuilder
    end function

    function buildPlane(PlaneBuilder planeBuilder): PlaneBuilder
        planeBuilder.addWheel(3)
        planeBuilder.addEngine(2)
        planeBuilder.addDoor(4)
        planeBuilder.addSeat(120)
        planeBuilder.addInterior()
        planeBuilder.addWing(2)

        return planeBuilder
    end function

end class

Demo

  • For using the builder pattern, create a producer(VehicleProducer) object.
  • Then create object of builder classes(CarBuilder and PlaneBuilder).
  • Pass the builder object to the producer and call the build method. That will generate the desired object.
VehicleProducer vehicleProducer = new VehicleProducer()

print("Building Car:")

CarBuilder carBuilder = new CarBuilder()
vehicleProducer.buildCar(carBuilder)

Car car = carBuilder.build()
print("Final result:" + car)


print("Building Car:")

PlaneBuilder planeBuilder = new PlaneBuilder()
vehicleProducer.buildPlane(planeBuilder)

Plane plane = planeBuilder.build()
print("Final result:" + plane)

Output

Output of the code above will be as below.

Building Car:

Add 4 wheels
Add 1 engine
Add 4 door
Add 4 Seat
Add interior

Final result:
Car: Wheel -> 4 | Engine -> 1 | Seat -> 4 | Door -> 4 | Interior -> true
----------------------------
Building Car:

Add 3 wheels
Add 2 engine
Add 4 door
Add 120 Seat
Add interior
Add 2 wing

Final result:
Plane: Wheel -> 3 | Engine -> 2 | Seat -> 120 | Door -> 4 | Wing: 0 | Interior -> true

Code Implementations

Use the following links to check Builder pattern implementation in specific programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.