
Introduction
An essential skill for those involved in AI development is to write clean, reusable code. Therefore, today I will introduce another design pattern in Python using Deepnote.
It doesn’t matter how good you are at Deep Learning topics, statistics or anything else, if your code is not clean and easily reusable you will never be able to develop something that will have a major impact. That’s why I think it’s very important for data scientists to have software engineering skills. Design patterns are something that all people who write code should know. Today we are going to talk about the pattern called Builder.
What is a Design Pattern?
A design pattern is simply a general design solution to a recurring problem. Instead of dealing with solving the same problem over and over again, one thinks of a solution that can be used every time the same problem is encountered, and these solutions have already been found! Someone has fortunately already thought of making our lives easier! 🙂
Desgin patterns differ in several kinds. But mainly we have 3 of them:
- Creational: it’s about the process of creating objects.
- Structural: it’s about the composition of classes and objects.
-
Behavioural: defines how classes and objects interact and distribute responsibilities among themselves.

The Builder Design Pattern
The builder is part of that design pattern class called creational, because it precisely simplifies the creation of objects within the code. Imagine that you have a class, which requires an immense number of parameters to be instantiated, or for Pythonians, a class whose init() method expects lots of input parameters.
Imagine you have a class to design a park, perhaps because you are creating the environment for a video game. You can customize the park in various ways, adding and removing various things. You can add games, children, or create a park full of animals and more.

But at the implementation level, how do we deal with implementing all these kinds of parks? The most intuitive solution is probably to create a base Park class, which other classes will then extend to include the various features. But in this case we will end up with four subclasses, and in real projects we will have an immense number of subclasses, which would make our code impractical.
Or we could create just one class, the class Park, and use a huge constructor to which a lot of parameters can be given as input. But the problem is that in most cases the input parameters would be null, because we don’t always want to create a park that has everything, and again the code would look a little ugly.
The solution adopted by the Builder, is to create all the various features we want to include in different methods of the Park class, called builders, instead of having everything inside the constructor. This way we can build the pieces of our Park step-by-step, depending on what we need.

Let’s code!
Let’s see how to implement this design pattern in Python now. In this example what we want to do is to build different types of robots that have different configurations. The following code will consist of 5 basic parts.
- Robot Class:
- First, we create the
Robot
class that represents the objects we want to build with all their attributes such ashead
,arms
,legs
,torso
, andbattery
.
# Define the Robot class
class Robot:
def __init__(self):
self.head = None
self.arms = None
self.legs = None
self.torso = None
self.battery = None
2. Builder Interface:
- The
RobotBuilder
interface is an abstract class that defines a set of methods for building the different parts of aRobot
object. These methods includereset
,build_head
,build_arms
,build_legs
,build_torso
,build_battery
, andget_robo
.
from abc import ABC, abstractmethod
class RobotBuilder(ABC):
@abstractmethod
def reset(self):
pass
@abstractmethod
def build_head(self):
pass
@abstractmethod
def build_arms(self):
pass
@abstractmethod
def build_legs(self):
pass
@abstractmethod
def build_torso(self):
pass
@abstractmethod
def build_battery(self):
pass
@abstractmethod
def get_robot(self):
pass
3. Concrete Builders:
- Now we have the builder classes that implements the abstract class
RobotBuilder
which areHumanoidRobotBuilder
andDroneRobotBuilder
. These builders give to robots different settings that differentiate them from each other. - Remember that each builder maintains an instance of the
Robot
it’s constructing.
# Define a Concrete Builder for a Robot
class HumanoidRobotBuilder(RobotBuilder):
def __init__(self):
self.robot = Robot()
self.reset()
def reset(self):
self.robot = Robot()
def build_head(self):
self.robot.head = "Humanoid Head"
def build_arms(self):
self.robot.arms = "Humanoid Arms"
def build_legs(self):
self.robot.legs = "Humanoid Legs"
def build_torso(self):
self.robot.torso = "Humanoid Torso"
def build_battery(self):
self.robot.battery = "Humanoid Battery"
def get_robot(self):
return self.robot
# Define a Concrete Builder for a Robot
class DroneRobotBuilder(RobotBuilder):
def __init__(self):
self.robot = Robot()
self.reset()
def reset(self):
self.robot = Robot()
def build_head(self):
self.robot.head = "Drone Head"
def build_arms(self):
self.robot.arms = "No Arms"
def build_legs(self):
self.robot.legs = "No Legs"
def build_torso(self):
self.robot.torso = "Drone Torso"
def build_battery(self):
self.robot.battery = "Drone Battery"
def get_robot(self):
return self.robot
4. RobotDirector:
- The class called
RobotDirector
has the task of directing the construction of robots using specific builders it has available. - Inside this class, you will find the
set_builder
method to activate the builder you need and duibuild_humanoid_robot
andbuild_drone_robot
methods to create different types of robots - The director’s methods return the final constructed robot objects.
# Define the RobotDirector class with methods to create different robots
class RobotDirector:
def __init__(self):
self.builder = None
def set_builder(self, builder):
self.builder = builder
def build_humanoid_robot(self):
self.builder.reset()
self.builder.build_head()
self.builder.build_arms()
self.builder.build_legs()
self.builder.build_torso()
self.builder.build_battery()
return self.builder.get_robot()
def build_drone_robot(self):
self.builder.reset()
self.builder.build_head()
self.builder.build_torso()
self.builder.build_battery()
return self.builder.get_robot()
5. Client Code:
- Let’s create a
RobotDirector
instance. - Then create a
HumanoidRobotBuilder
and set it as the active builder for humanoid robots. - We also use the director’s
build_humanoid_robot
method to create a humanoid robot. - Now we can create a
DroneRobotBuilder
and set it as the active builder for drone robots. - Now we have to use the director’s
build_drone_robot
method to create a drone robot. - Finally, we print out the components of both types of robots.
# Client code
if __name__ == "__main__":
director = RobotDirector()
humanoid_builder = HumanoidRobotBuilder()
director.set_builder(humanoid_builder)
humanoid_robot = director.build_humanoid_robot()
drone_builder = DroneRobotBuilder()
director.set_builder(drone_builder)
drone_robot = director.build_drone_robot()
print("Humanoid Robot Components:")
print(f"Head: {humanoid_robot.head}")
print(f"Arms: {humanoid_robot.arms}")
print(f"Legs: {humanoid_robot.legs}")
print(f"Torso: {humanoid_robot.torso}")
print(f"Battery: {humanoid_robot.battery}")
print("nDrone Robot Components:")
print(f"Head: {drone_robot.head}")
print(f"Arms: {drone_robot.arms}")
print(f"Legs: {drone_robot.legs}")
print(f"Torso: {drone_robot.torso}")
print(f"Battery: {drone_robot.battery}")
That’s it! 😊
Final Thoughts
The Builder pattern decouples the construction of a complex object from its representation. As we have seen in this example, the RobotDirector is in charge of orchestrating the construction process but is not aware of the specific steps to create different types of robots. The concrete builders, which we called HumanoidRobotBuilder and DroneRobotBuilder in this case, provide step-by-step implementations for building specific robot configurations.
The pattern allows flexibility and extensibility, enabling the creation of complex objects with variable attributes while keeping client code clean and easy to use. All this allows us to build complex objects in a clear and consistent way.
If you were interested in this article follow me on Medium! 😁
💼 Linkedin ️| 🐦 Twitter | 💻 Website
You might be interested in some of my past articles as well: