Creational Design Patterns provide solution to instantiate an object in the best possible way for specific situations. Following design patterns come under this category.
Builder pattern allows you to create different flavors of an object while avoiding constructor pollution. Useful when there could be several flavors of an object.
Builder pattern builds a complex object using simple objects and using a step by step approach.
It is mostly used when object can't be created in single step like in the de-serialization of a complex object.
The intent of the Builder Pattern is to separate the construction of a complex object from its representation, so that the same construction process can create different representations. This type of separation reduces the object size. The design turns out to be more modular with each implementation contained in a different builder object. Adding a new implementation (i.e., adding a new builder) becomes easier. The object construction process becomes independent of the components that make up the object. This provides more control over the object construction process.
The Builder pattern suggests using a dedicated object referred to as a Director, which is responsible for invoking different builder methods required for the construction of the final object. Different client objects can make use of the Director object to create the required object. Once the object is constructed, the client object can directly request from the builder the fully constructed object. To facilitate this process, a new method getResult
can be declared in the common Builder interface to be implemented by different concrete builders.
The classes and objects participating in this pattern are:
Builder
(VehicleBuilder)Product
objectConcreteBuilder
(MotorCycleBuilder, CarBuilder, ScooterBuilder)Builder
interfaceDirector
(Shop)Builder
interfaceProduct
(Vehicle)ConcreteBuilder
builds the product's internal representation and defines the process by which it's assembledAdvantage of Builder design pattern:
Builder Pattern is used when:
Java
// represents the product created by the builder. class Car { private String color; public Car() {} @Override public String toString() { return "Car [color=" + color + "]"; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } } // the builder abstraction interface CarBuilder { void setColor(String color); Car getResult(); } class CarBuilderImpl implements CarBuilder { private Car car; public CarBuilderImpl() { car = new Car(); } @Override public void setColor(String color) { car.setColor(color); } @Override public Car getResult() { return car; } } public class CarBuildDirector { private CarBuilder builder; public CarBuildDirector(CarBuilder builder) { this.builder = builder; } public Car construct() { builder.setColor("Red"); return builder.getResult(); } public static void main(String[] args) { CarBuilder builder = new CarBuilderImpl(); CarBuildDirector carBuildDirector = new CarBuildDirector(builder); System.out.println(carBuildDirector.construct()); } }
Python 3
import abc # represents the product created by the builder. class Car: def __init__(self): self.color = None def get_color(self): return self.color def set_color(self, color): self.color = color def __str__(self): return "Car [color={0}]".format(self.color) # the builder abstraction class CarBuilder(metaclass=abc.ABCMeta): @abc.abstractmethod def set_color(self, color): pass @abc.abstractmethod def get_result(self): pass class CarBuilderImpl(CarBuilder): def __init__(self): self.car = Car() def set_color(self, color): self.car.set_color(color) def get_result(self): return self.car class CarBuildDirector: def __init__(self, builder): self.builder = builder def construct(self): self.builder.set_color("Red"); return self.builder.get_result() if __name__ == '__main__': builder = CarBuilderImpl() carBuildDirector = CarBuildDirector(builder) print(carBuildDirector.construct())
Kotlin
Like some other modern languages, Kotlin provides us with the ability to set default values for function parameters:
data class Mail(val to: String, val title: String = "", val message: String = "", val cc: List<String> = listOf(), val bcc: List<String> = listOf(), val attachments: List<java.io.File> = listOf())
So, if you would like to send an email without CC, you can do it like that now:
val mail = Mail("one@recepient.org", "Hi", "How are you")
You can create a full-blown builder design pattern:
class MailBuilder(val to: String) { private var mail: Mail = Mail(to) fun title(title: String): MailBuilder { mail.title = title return this } // Repeated for other properties fun build(): Mail { return mail } }
You can use it to create your email in the following way:
val email = MailBuilder("hello@hello.com").title("What's up?").build()