Builder¶
Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
- Seperates the construction of an object from it's representation
- Encapsulates object construction
- Multi step construction process
- Implementations can vary
- Client only sees the abstraction
Product:¶
It's used by the Concrete Builder
class. It contains the attributes and functionalities of the class.
Builder:¶
It's abstract class which contains the methods that will be implemented by the Concrete Builder
.
Concrete Builder:¶
It implements the methods defined in the abstrct Builder
class and it uses the objects of class Product
.
Director:¶
It takes the Concrete Builder
object and it's method construct()
performs the step by step operations and returns the object to assemble the product parts.
Client:¶
It uses the classes Director
and Builder
and their methods to get the required output.
Builder pattern implementation¶
Let's consider the scenario of building a house. To build the house we need to build basement, walls, windows, roof.
we need the following steps
- build basement
- build walls
- build windows
- buils doors
- build roof
step1: Let's write the code for the product class House
class House:
basement = None
walls = None
windows = None
doors = None
roof = None
def get_info(self):
print(f"basement: {self.basement}")
print(f"walls: {self.walls}")
print(f"windows: {self.windows}")
print(f"doors: {self.doors}")
print(f"roof: {self.roof}\n")
step2: Let's create the abstract builder class AbsHouseBuilder
which contains the required methods to build the house.
from abc import ABC, abstractmethod
class AbsHouseBuilder(ABC):
house = None
@abstractmethod
def build_basement(self):
pass
@abstractmethod
def build_walls(self):
pass
@abstractmethod
def build_windows(self):
pass
@abstractmethod
def build_doors(self):
pass
@abstractmethod
def build_roof(self):
pass
step3: Let's create the concrete builder class SimpleHouseBuilder
which implements the abstract methods defined in the class AbsHouseBuilder
.
class SimpleHouseBuilder(AbsHouseBuilder):
def __init__(self):
self.house = House()
def build_basement(self):
self.house.basement = "rock solid basement"
def build_walls(self):
self.house.walls = "4 sand brick walls"
def build_windows(self):
self.house.windows = "2 wooden windows"
def build_doors(self):
self.house.doors = "2 wooden doors"
def build_roof(self):
self.house.roof = "Gable roof"
def get_house(self):
return self.house
step4: Let's create a director class HouseDirector
which will call the builder methods in a specific order to build the product i.e simple house.
class HouseDirector:
def __init__(self, builder):
self.builder = builder
def construct(self):
self.builder.build_basement()
self.builder.build_walls()
self.builder.build_windows()
self.builder.build_doors()
self.builder.build_roof()
return self.builder.get_house()
step5: Let's use the defined classes HouseDirector
and SimpleHouseBuilder
to create the simple house.
if __name__ == '__main__':
builder = SimpleHouseBuilder()
director = HouseDirector(builder)
house = director.construct()
house.get_info()
Once, we combine all the above and execute it then it will give us the below output
basement: rock solid basement
walls: 4 sand brick walls
windows: 2 wooden windows
doors: 2 wooden doors
roof: Gable roof
Now, let's say if we want to build a Igloo
house then we just need to write IglooHouseBuilder
and implement the respective methods and reuse the existing code.
class IglooHouseBuilder(AbsHouseBuilder):
def __init__(self):
self.house = House()
def build_basement(self):
self.house.basement = "Ice basement"
def build_walls(self):
self.house.walls = "round wall"
def build_windows(self):
self.house.windows = "no windows"
def build_doors(self):
self.house.doors = "1 wooden door"
def build_roof(self):
self.house.roof = "Ice roof"
def get_house(self):
return self.house
Now, let's update the client code to use the both builders classes
if __name__ == '__main__':
builders = [SimpleHouseBuilder(), IglooHouseBuilder()]
for builder in builders:
director = HouseDirector(builder)
house = director.construct()
house.get_info()
It gives the below output
basement: rock solid basement
walls: 4 sand brick walls
windows: 2 wooden windows
doors: 2 wooden doors
roof: Gable roof
basement: Ice basement
walls: round wall
windows: no windows
doors: 1 wooden door
roof: Ice roof