The builder pattern, also known as the builder pattern, is an object-built design pattern. It is used to create complex objects, separating the construction of a complex object from the representation, so that the same construction process can create different representations. It consists of four roles: Product, Builder, ConcreteBuilder, and Director.
Imagine a complex object that requires laborious, step-by-step initialization of many fields and nested objects. This type of initialization is often hidden in a huge constructor with a large number of parameters.
For example, let's consider how to create a house object. To build a simple house, you need to build four walls and a floor, install a door, install a pair of windows, and then build a roof. But what if you want a bigger, brighter house with a backyard and other amenities like heating, plumbing, and wiring?
The simplest solution is to extend the house base class and create a set of subclasses to cover all combinations of parameters. But in the end you'll get quite a few subclasses. Any new parameters, such as the porch style, need to further develop this hierarchy.
There is another way that doesn't involve creating subclasses. You can create a huge constructor in the house base class that contains all the possible parameters that control the house object. While this approach does eliminate the need for subclasses, it creates another problem. In most cases, most arguments are not used, which makes constructor calls very ugly. For example, only a small percentage of houses have swimming pools, so the parameters associated with swimming pools are useless.
Builder mode recommends that you take an object from its own class to build and move it to a separate object called the builder.
This pattern organizes object construction into a set of steps (buildwalls, builddoor, and so on). To create an object, you need to perform a series of these steps on the builder object. The important thing is that you don't need to call all the steps. You can only invoke those steps that are required for a specific configuration of the resulting object. When you need to build various representations of a product, some build steps may require different implementations. For example, the walls of a cottage can be built of wood, but the walls of a castle must be made of stone.
In this case, you can create multiple different builder classes that implement the same set of build steps in different ways. You can then use these builders to generate different types of objects during the build process, which is an ordered set of calls to build steps.
Specifically, it consists of four roles: Product, Builder, ConcreteBuilder, and Director.
builder
The builder interface declares product build steps that are common to all types of builders.
concretebuilder
Concrete Builders provides different implementations of the same build step.
Director
Extract a series of calls to the builder steps used to build the product into a separate class called director. The Director class defines the order in which the build steps are executed, while the builder provides the implementation of those steps.
The client must associate one of the builder objects with the director. Usually, it only needs to be done once via the arguments of the director constructor. The director then uses that builder object for all further builds.
it makes sense to use the builder pattern only when your products are quiteThe objects that need to be generated have complex internal structures.complex and require extensive configuration.
unlike in other creational patterns, different concrete builders can produce
unrelated products. in other words, results of various builders may not
always follow the same interface.
class product1else
std::cout <
the builder interface specifies methods for creating the different parts of
the product objects.
class builder
virtual void produceparta() const =0;
virtual void producepartb() const =0;
virtual void producepartc() const =0;
the concrete builder classes follow the builder interface and provide
specific implementations of the building steps. your program may h**e several
variations of builders, implemented differently.
class concretebuilder1 : public builder
concretebuilder1()
void reset()
all production steps work with the same product instance.
void produceparta()const override
void producepartb()const override
void producepartc()const override
concrete builders are supposed to provide their own methods for
retrieving results. that's because various types of builders may create
entirely different products that don't follow the same interface.
therefore, such methods cannot be declared in the base builder interface
at least in a statically typed programming language). note that php is a
dynamically typed language and this method can be in the base interface.
however, we won't declare it there for the sake of clarity.
usually, after returning the end result to the client, a builder instance
is expected to be ready to start producing another product. that's why
it's a usual practice to call the reset method at the end of the
getproduct` method body. however, this beh**ior is not mandatory, and
you can make your builders wait for an explicit reset call from the
client code before disposing of the previous result.
please be careful here with the memory ownership. once you call
getproduct the user of this function is responsable to release this
memory. here could be a better option to use smart pointers to **oid
memory leaks
product1* getproduct()
the director is only responsible for executing the building steps in a
particular sequence. it is helpful when producing products according to a
specific order or configuration. strictly speaking, the director class is
optional, since the client can control builders directly.
class director
the director can construct several product variations using the same
building steps.
void buildminimalviableproduct()
void buildfullfeaturedproduct()
the client code creates a builder object, passes it to the director and then
initiates the construction process. the end result is retrieved from the
builder object.
i used raw pointers for simplicity however you may prefer to use smart
pointers here
void clientcode(director& director)
concretebuilder1* builder = new concretebuilder1();
director.set_builder(builder);
std::cout <
director.buildminimalviableproduct();
product1* p= builder->getproduct();
p->listparts();
delete p;
std::cout <
director.buildfullfeaturedproduct();
p= builder->getproduct();
p->listparts();
delete p;
remember, the builder pattern can be used without a director class.
std::cout <
builder->produceparta();
builder->producepartc();
p=builder->getproduct();
p->listparts();
delete p;
delete builder;
int main()", end="")
class director:
the director is only responsible for executing the building steps in a
particular sequence. it is helpful when producing products according to a
specific order or configuration. strictly speaking, the director class is
optional, since the client can control builders directly.
def __init__(self) -none:
self._builder = none
property
def builder(self) -builder:
return self._builder
builder.setter
def builder(self, builder: builder) -none:
the director works with any builder instance that the client code passes
to it. this way, the client code may alter the final type of the newly
assembled product.
self._builder = builder
the director can construct several product variations using the same
building steps.
def build_minimal_viable_product(self) -none:
self.builder.produce_part_a()
def build_full_featured_product(self) -none:
self.builder.produce_part_a()
self.builder.produce_part_b()
self.builder.produce_part_c()
if __name__ == "__main__":
the client code creates a builder object, passes it to the director and then
initiates the construction process. the end result is retrieved from the
builder object.
director = director()
builder = concretebuilder1()
director.builder = builder
print("standard basic product: ")
director.build_minimal_viable_product()
builder.product.list_parts()
print("")
print("standard full featured product: ")
director.build_full_featured_product()
builder.product.list_parts()
print("")
# remember, the builder pattern can be used without a director class.
print("custom product: ")
builder.produce_part_a()
builder.produce_part_b()
builder.product.list_parts()
The builder pattern encapsulates the specific generation process and details, so that the object can be generated without knowing all the details.
The internal properties of the objects that need to be generated depend on each other.
The builder pattern forces the user to generate objects through a specific process.
Complex objects that want fine-grained control over the internal state during construction.
For example, build a complex, multi-layered nested XML document or HTML.
Better encapsulation.
The user doesn't have to know the implementation details inside the product.
Better scalability.
The builder is completely independent, and the system can extend its precision.
Flexibility. The customer can control the product creation process, the director uses the builder interface, and the replacement or expansion of the builder has little impact on the director class.
This causes the number of classes in the system to increase.
The builder pattern abstracts parts of the system into new classes, so the number of system classes increases.
Increased complexity of the system: multiple new classes were introduced, and there was bound to be a deeper dependency between the commander and the concrete builder.