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()