The Builder Design Pattern is a creational design pattern that provides a step-by-step approach to constructing complex objects. It separates the construction process from the object’s representation, enabling the same method to create different variations of an object.
- Encapsulates object construction logic in a separate Builder class, enabling flexible and controlled creation.
- Supports creating different variations of a product using the same construction process.
Example: Consider building an SQL query in a database application. A query can have different parts like select fields, conditions, sorting, and limits.

Instead of using a complex constructor with many parameters, the Builder pattern allows you to construct it step by step:
- Select columns
- Add conditions (WHERE clause)
- Set order (optional)
- Set limit (optional)
Using the same building process, you can create different queries like simple queries, filtered queries, or sorted queries without changing the main code.
Real-Life Applications
The Builder Pattern is widely used in real-life software applications to construct complex objects step by step.
- SQL Query Builders: Used in ORMs (like Hibernate, SQLAlchemy, Laravel’s Eloquent) to dynamically construct SQL queries with methods like select(), where(), orderBy(), etc.
- UI Component Builders: Useful in building dialog boxes, forms or widgets step by step by adding buttons, text fields or styles.
- Document Builders: Used in tools like PDF/HTML generators, where content and styles are added step by step.
Components
The Builder Pattern consists of several key components that work together to construct complex objects step by step while keeping construction separate from representation.
- Product: The complex object being constructed, typically a class with attributes representing different parts built by the Builder.
- Builder: An interface or abstract class that defines construction steps, including methods to build individual parts of the product.
- Concrete Builder: Implements the Builder interface, providing specific logic to construct each part and create a particular variation of the product.
- Director: Manages the construction process by working with a Builder, without knowing the internal details of how parts are created.
- Client: Initiates the construction by creating a Builder and passing it to the Director to build the final product.
Uses
The Builder Pattern is helpful when creating complex objects with multiple optional steps or configurations.
- Useful for complex objects with many optional steps.
- Separates construction logic from object representation.
- Avoids telescoping constructors with too many parameters.
- Supports creating different representations using the same construction process.
Implementation
The steps to implement the Builder Design Pattern:
- Create the Product Class: Define the object (product) that will be built. This class contains all the fields that make up the object.
- Create the Builder Class: This class will have methods to set the different parts of the product. Each method returns the builder itself to allow method chaining.
- Add a Build Method: In the builder class, add a method called build() (or similar) that assembles the product and returns the final object.
- Use the Director (Optional): If needed, you can create a director class to control the building process and decide the order in which parts are constructed.
- Client Uses the Builder: The client will use the builder to set the desired parts step by step and call the build() method to get the final product.
Understanding the Builder Design Pattern in a simple and beginner-friendly way.
Implementation Example
Problem Statement
You are tasked with implementing a system for building custom computers. Each computer can have different configurations based on user preferences. The goal is to provide flexibility in creating computers with varying CPUs, RAM, and storage options.
Implement the Builder design pattern to achieve this, allowing the construction of computers through a step-by-step process. Use the provided components - Product (Computer), Builder interface, ConcreteBuilder (GamingComputerBuilder), Director, and Client

1. Product (Computer)
The final complex object that is created using the Builder pattern.
// Product
class Computer {
private:
string cpu_;
string ram_;
string storage_;
public:
void setCPU(const std::string& cpu) {
cpu_ = cpu;
}
void setRAM(const std::string& ram) {
ram_ = ram;
}
void setStorage(const std::string& storage) {
storage_ = storage;
}
void displayInfo() const {
std::cout << "Computer Configuration:"
<< "\nCPU: " << cpu_
<< "\nRAM: " << ram_
<< "\nStorage: " << storage_ << "\n\n";
}
};
/* Product */
class Computer {
private String cpu_;
private String ram_;
private String storage_;
public void setCPU(String cpu) {
cpu_ = cpu;
}
public void setRAM(String ram) {
ram_ = ram;
}
public void setStorage(String storage) {
storage_ = storage;
}
public void displayInfo() {
System.out.println("Computer Configuration:"
+ "\nCPU: " + cpu_
+ "\nRAM: " + ram_
+ "\nStorage: " + storage_ + "\n\n");
}
}
""" Product """
class Computer:
def __init__(self):
self.cpu_ = ""
self.ram_ = ""
self.storage_ = ""
def setCPU(self, cpu):
self.cpu_ = cpu
def setRAM(self, ram):
self.ram_ = ram
def setStorage(self, storage):
self.storage_ = storage
def displayInfo(self):
print(f'Computer Configuration:\nCPU: {self.cpu_}\nRAM: {self.ram_}\nStorage: {self.storage_}\n\n')
/* Product */
class Computer {
constructor() {
this.cpu_ = "";
this.ram_ = "";
this.storage_ = "";
}
setCPU(cpu) {
this.cpu_ = cpu;
}
setRAM(ram) {
this.ram_ = ram;
}
setStorage(storage) {
this.storage_ = storage;
}
displayInfo() {
console.log(`Computer Configuration:\nCPU: ${this.cpu_}\nRAM: ${this.ram_}\nStorage: ${this.storage_}\n\n`);
}
}
2. Builder
An interface/abstract class that defines step-by-step methods to create different parts of the Product (Computer).
// Builder interface
class Builder {
public:
virtual void buildCPU() = 0;
virtual void buildRAM() = 0;
virtual void buildStorage() = 0;
virtual Computer getResult() = 0;
};
/* Builder interface */
interface Builder {
void buildCPU();
void buildRAM();
void buildStorage();
Computer getResult();
}
""" Builder interface """
from abc import ABC, abstractmethod
class Builder(ABC):
@abstractmethod
def buildCPU(self):
pass
@abstractmethod
def buildRAM(self):
pass
@abstractmethod
def buildStorage(self):
pass
@abstractmethod
def getResult(self):
pass
/* Builder interface */
class Builder {
buildCPU() {
throw new Error("Method not implemented.");
}
buildRAM() {
throw new Error("Method not implemented.");
}
buildStorage() {
throw new Error("Method not implemented.");
}
getResult() {
throw new Error("Method not implemented.");
}
}
3. Concrete Builder (Gaming Computer Builder)
A specific builder class that implements the Builder steps to create a gaming computer configuration.
#include <string>
#include <memory>
class Computer {
public:
void setCPU(const std::string& cpu) { cpu_ = cpu; }
void setRAM(const std::string& ram) { ram_ = ram; }
void setStorage(const std::string& storage) { storage_ = storage; }
private:
std::string cpu_;
std::string ram_;
std::string storage_;
};
class Builder {
public:
virtual void buildCPU() = 0;
virtual void buildRAM() = 0;
virtual void buildStorage() = 0;
virtual std::unique_ptr<Computer> getResult() = 0;
};
class GamingComputerBuilder : public Builder {
private:
std::unique_ptr<Computer> computer_ = std::make_unique<Computer>();
public:
void buildCPU() override {
computer_->setCPU("Gaming CPU");
}
void buildRAM() override {
computer_->setRAM("16GB DDR4");
}
void buildStorage() override {
computer_->setStorage("1TB SSD");
}
std::unique_ptr<Computer> getResult() override {
return std::move(computer_);
}
};
// ConcreteBuilder
class GamingComputerBuilder implements Builder {
private Computer computer_ = new Computer();
@Override
public void buildCPU() {
computer_.setCPU("Gaming CPU");
}
@Override
public void buildRAM() {
computer_.setRAM("16GB DDR4");
}
@Override
public void buildStorage() {
computer_.setStorage("1TB SSD");
}
@Override
public Computer getResult() {
return computer_;
}
}
class Computer:
def __init__(self):
self.cpu = None
self.ram = None
self.storage = None
class Builder:
def buildCPU(self):
pass
def buildRAM(self):
pass
def buildStorage(self):
pass
def getResult(self):
pass
class GamingComputerBuilder(Builder):
def __init__(self):
self.computer_ = Computer()
def buildCPU(self):
self.computer_.cpu = "Gaming CPU"
def buildRAM(self):
self.computer_.ram = "16GB DDR4"
def buildStorage(self):
self.computer_.storage = "1TB SSD"
def getResult(self):
return self.computer_
class Computer {
constructor() {
this.cpu = null;
this.ram = null;
this.storage = null;
}
}
class Builder {
buildCPU() {}
buildRAM() {}
buildStorage() {}
getResult() {}
}
class GamingComputerBuilder extends Builder {
constructor() {
super();
this.computer_ = new Computer();
}
buildCPU() {
this.computer_.cpu = "Gaming CPU";
}
buildRAM() {
this.computer_.ram = "16GB DDR4";
}
buildStorage() {
this.computer_.storage = "1TB SSD";
}
getResult() {
return this.computer_;
}
}
4. Director
A class that controls the building process by calling builder methods in the correct order to construct the product.
// Director
class ComputerDirector {
public:
void construct(Builder& builder) {
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
}
};
/* Director */
public class ComputerDirector {
public void construct(Builder builder) {
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
}
}
""" Director """
class ComputerDirector:
def __init__(self):
pass
def construct(self, builder):
builder.buildCPU()
builder.buildRAM()
builder.buildStorage()
/* Director */
class ComputerDirector {
constructor() {}
construct(builder) {
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
}
}
5. Client
The user/code that selects a builder, starts the building process, and finally gets the completed product.
#include <iostream>
#include "GamingComputerBuilder.h"
#include "ComputerDirector.h"
#include "Computer.h"
int main() {
GamingComputerBuilder gamingBuilder;
ComputerDirector director;
director.construct(gamingBuilder);
Computer gamingComputer = gamingBuilder.getResult();
gamingComputer.displayInfo();
return 0;
}
// Client
public class Main {
public static void main(String[] args) {
GamingComputerBuilder gamingBuilder = new GamingComputerBuilder();
ComputerDirector director = new ComputerDirector();
director.construct(gamingBuilder);
Computer gamingComputer = gamingBuilder.getResult();
gamingComputer.displayInfo();
}
}
from GamingComputerBuilder import GamingComputerBuilder
from ComputerDirector import ComputerDirector
from Computer import Computer
# Client
def main():
gamingBuilder = GamingComputerBuilder()
director = ComputerDirector()
director.construct(gamingBuilder)
gamingComputer = gamingBuilder.getResult()
gamingComputer.displayInfo()
if __name__ == "__main__":
main()
const { GamingComputerBuilder } = require('./GamingComputerBuilder');
const { ComputerDirector } = require('./ComputerDirector');
const { Computer } = require('./Computer');
// Client
function main() {
const gamingBuilder = new GamingComputerBuilder();
const director = new ComputerDirector();
director.construct(gamingBuilder);
const gamingComputer = gamingBuilder.getResult();
gamingComputer.displayInfo();
}
main();
Complete Combined code for the above example
#include <iostream>
#include <string>
using namespace std;
// Product
class Computer
{
public:
void setCPU(const std::string &cpu)
{
cpu_ = cpu;
}
void setRAM(const std::string &ram)
{
ram_ = ram;
}
void setStorage(const std::string &storage)
{
storage_ = storage;
}
void displayInfo() const
{
std::cout << "Computer Configuration:"
<< "\nCPU: " << cpu_ << "\nRAM: " << ram_ << "\nStorage: " << storage_ << "\n\n";
}
private:
string cpu_;
string ram_;
string storage_;
};
// Builder interface
class Builder
{
public:
virtual void buildCPU() = 0;
virtual void buildRAM() = 0;
virtual void buildStorage() = 0;
virtual Computer getResult() = 0;
};
// ConcreteBuilder
class GamingComputerBuilder : public Builder
{
private:
Computer computer_;
public:
void buildCPU() override
{
computer_.setCPU("Gaming CPU");
}
void buildRAM() override
{
computer_.setRAM("16GB DDR4");
}
void buildStorage() override
{
computer_.setStorage("1TB SSD");
}
Computer getResult() override
{
return computer_;
}
};
// Director
class ComputerDirector
{
public:
void construct(Builder &builder)
{
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
}
};
// Client
int main()
{
GamingComputerBuilder gamingBuilder;
ComputerDirector director;
director.construct(gamingBuilder);
Computer gamingComputer = gamingBuilder.getResult();
gamingComputer.displayInfo();
return 0;
}
// Product
class Computer {
private String cpu;
private String ram;
private String storage;
public void setCPU(String cpu) { this.cpu = cpu; }
public void setRAM(String ram) { this.ram = ram; }
public void setStorage(String storage)
{
this.storage = storage;
}
public void displayInfo()
{
System.out.println("Computer Configuration:\n"
+ "CPU: " + cpu + "\n"
+ "RAM: " + ram + "\n"
+ "Storage: " + storage + "\n");
}
}
// Builder interface
interface Builder {
void buildCPU();
void buildRAM();
void buildStorage();
Computer getResult();
}
// ConcreteBuilder
class GamingComputerBuilder implements Builder {
private Computer computer = new Computer();
public void buildCPU()
{
computer.setCPU("Gaming CPU");
}
public void buildRAM() { computer.setRAM("16GB DDR4"); }
public void buildStorage()
{
computer.setStorage("1TB SSD");
}
public Computer getResult() { return computer; }
}
// Director
class ComputerDirector {
public void construct(Builder builder)
{
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
}
}
// Client
public class Main {
public static void main(String[] args)
{
GamingComputerBuilder gamingBuilder
= new GamingComputerBuilder();
ComputerDirector director = new ComputerDirector();
director.construct(gamingBuilder);
Computer gamingComputer = gamingBuilder.getResult();
gamingComputer.displayInfo();
}
}
class Computer:
def __init__(self):
self.cpu = None
self.ram = None
self.storage = None
def set_cpu(self, cpu):
self.cpu = cpu
def set_ram(self, ram):
self.ram = ram
def set_storage(self, storage):
self.storage = storage
def display_info(self):
print(
f'Computer Configuration:\nCPU: {self.cpu}\nRAM: {self.ram}\nStorage: {self.storage}\n')
# Builder interface
class Builder:
def build_cpu(self):
pass
def build_ram(self):
pass
def build_storage(self):
pass
def get_result(self):
pass
# ConcreteBuilder
class GamingComputerBuilder(Builder):
def __init__(self):
self.computer = Computer()
def build_cpu(self):
self.computer.set_cpu('Gaming CPU')
def build_ram(self):
self.computer.set_ram('16GB DDR4')
def build_storage(self):
self.computer.set_storage('1TB SSD')
def get_result(self):
return self.computer
# Director
class ComputerDirector:
def construct(self, builder):
builder.build_cpu()
builder.build_ram()
builder.build_storage()
# Client
if __name__ == '__main__':
gaming_builder = GamingComputerBuilder()
director = ComputerDirector()
director.construct(gaming_builder)
gaming_computer = gaming_builder.get_result()
gaming_computer.display_info()
class Computer {
constructor()
{
this.cpu = null;
this.ram = null;
this.storage = null;
}
setCPU(cpu) { this.cpu = cpu; }
setRAM(ram) { this.ram = ram; }
setStorage(storage) { this.storage = storage; }
displayInfo()
{
console.log(`Computer Configuration:\nCPU: ${
this.cpu}\nRAM: ${this.ram}\nStorage: ${
this.storage}\n`);
}
}
// Builder interface
class Builder {
buildCPU() {}
buildRAM() {}
buildStorage() {}
getResult() {}
}
// ConcreteBuilder
class GamingComputerBuilder extends Builder {
constructor()
{
super();
this.computer = new Computer();
}
buildCPU() { this.computer.setCPU("Gaming CPU"); }
buildRAM() { this.computer.setRAM("16GB DDR4"); }
buildStorage() { this.computer.setStorage("1TB SSD"); }
getResult() { return this.computer; }
}
// Director
class ComputerDirector {
construct(builder)
{
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
}
}
// Client
const gamingBuilder = new GamingComputerBuilder();
const director = new ComputerDirector();
director.construct(gamingBuilder);
const gamingComputer = gamingBuilder.getResult();
gamingComputer.displayInfo();
Output
Computer Configuration: CPU: Gaming CPU RAM: 16GB DDR4 Storage: 1TB SSD
- The Computer class represents the final product being built.
- GamingComputerBuilder implements the Builder interface to define how each part of the Computer is created.
- ComputerDirector controls the building process, while the client uses the builder and director to assemble the product.
Note:
- The above example uses the classic Builder Pattern where the Director controls the construction process.
- This ensures a fixed sequence of object creation but limits client-side flexibility.
- In modern applications, a fluent builder approach is preferred, allowing the client to build objects step by step using method chaining.
Advantages
The Builder pattern improves flexibility and readability when creating complex objects.
- Builds complex objects step by step using a separate Builder class, improving control over object creation.
- Separates construction logic from representation, allowing flexible and reusable object creation.
- Supports creation of different variations of the same object using a consistent process.
- Improves readability by avoiding large constructors and can promote immutability of the final object.
Disadvantages
Although powerful, the Builder pattern can introduce additional structure and complexity.
- Increases the number of classes in the system
- Adds unnecessary complexity for simple objects
- Requires changes if the product structure changes significantly