What
Builder design pattern is a type of creational pattern for building or creating a complex product. In these cases, the product creation is complex because this involves multiple steps or several parameters . However, with a builder design pattern, we can build such products very easily. Basically, it supports steps by step construction of a complex product.
The builder pattern also supports same construction process for multiple product variants also. This is possible, when it is possible to build these variants with the same construction process (although with different sub-classes or parameters).
Why
Lets try to understand the need for a builder design pattern by understanding construction of a mobile phone. The mobile phone is a complex product, because there are several components inside it. The components are processor, memory, screen, battery, operating system, etc.
Therefore, in this example, firstly, we need to build these individual components, i.e., processor, memory, screen battery and operating system. There shall be different steps such as below –
- buildProcessor( )
- buildMemory( )
- buildScreen( )
- buildBattery( )
- buildOperatingSystem( )
Construct Mobile Phone without using Builder Design Pattern
#include<iostream> //Main Header
#include<string> //for strings
using namespace std; //for namespace
class MobilePhone
{
public:
void buildProcessor(std::string str)
{
cout<<"processor build "
<<str<<endl;
}
void buildMemory(std::string str)
{
cout<<"Memory build "
<<str<<endl;
}
void buildScreen(std::string str)
{
cout<<"Screen build "
<<str<<endl;
}
void buildOperatingSystem(std::string str)
{
cout<<"OS build "
<<str<<endl;
}
};
int main()
{
MobilePhone *m1 = new MobilePhone;
m1->buildProcessor("SingleCore");
m1->buildMemory("512Mb");
m1->buildScreen("TouchScreen");
m1->buildOperatingSystem("Android");
}
As we know that the class MobilePhone construction required several steps. Therefore, in this case, the user or client class is building all components for Phone. The client is directly calling member functions for building of individual component.
The problem with this approach is that it is not futuristic. For example, we may need more steps such as build Port, build Input. It is also possible that the owner of class wants to change some steps. In such cases, it shall create a difficult condition. This is because, both MobilePhone Class as well as the client code shall have to change.
Another drawback of above approach is that the client also needs to keep knowledge of any parameter updates of individual components.
Builder design pattern to rescue
We need to resolve the above short comings in MobilePhone construction. Therefore, there is a need for design pattern which supports easy construction of a complex product for User. User should not involve in the internal steps of the product construction.
The Builder design pattern separates the construction of a product from its representation. This enables same construction process to create various product variants. The conclusion is that the builder pattern is the best.
How
Lets see below how to create MobilePhone with builder design pattern . Need to follow specific rules for using the builder design pattern.
- Firstly, create an abstract class, PhoneBuilder. This shall have interface for building individual components, such as Processor, Memory, Screen etc.
- Secondly, derive concrete classes from PhoneBuilder, such as, BasicPhoneBuilder, SmartPhoneAndriodBuilder , SmartPhoneiOSBuilder, etc. These classes will be having concrete implementation of different types of products.
- Finally, create a director class, PhoneDirector. This shall direct the abstract PhoneBuilder, how to create a mobile phone. It will be having high-level steps to build create exact product of user choice.
Mobile Phone example with builder design pattern
#include<iostream>
#include<string>
using namespace std;
class PhoneBuilder
{
public:
virtual void buildProcessor() =0;
virtual void buildMemory()=0;
virtual void buildScreen()=0;
virtual void buildOperatingSystem()=0;
};
class BasicPhoneBuilder:public PhoneBuilder
{
public:
void buildProcessor()
{
cout<<" Single Core"<<endl;
}
void buildMemory()
{
cout<<" 512 MB"<<endl;
}
void buildScreen()
{
cout<<"Touch screedn"<<endl;
}
void buildOperatingSystem()
{
cout<<"General OS"<<endl;
}
};
class SmartAndriodPhoneBuilder: public PhoneBuilder
{
public:
void buildProcessor()
{
cout<<" Quad Core"<<endl;
}
void buildMemory()
{
cout<<" 1 GB"<<endl;
}
void buildScreen()
{
cout<<"Touch screedn"<<endl;
}
void buildOperatingSystem()
{
cout<<"Andriod OS"<<endl;
}
};
class SmartApplePhoneBuilder:public PhoneBuilder
{
public:
void buildProcessor()
{
cout<<" Quad+Smart Core"<<endl;
}
void buildMemory()
{
cout<<" 5 GB"<<endl;
}
void buildScreen()
{
cout<<"Touch+ Senstivie screedn"<<endl;
}
void buildOperatingSystem()
{
cout<<"Apple OS"<<endl;
}
};
class PhoneDirector
{
PhoneBuilder *builder;
public:
void setPhoneBuilder(PhoneBuilder *p1)
{
builder=p1;
}
void constructMobile()
{
builder->buildProcessor();
builder->buildMemory();
builder->buildScreen();
builder->buildOperatingSystem();
}
};
int main()
{
PhoneDirector pd;
PhoneBuilder *pb1 = new SmartAndriodPhoneBuilder;
cout<<" Creating Andriod Phone ***********"<<endl;
pd.setPhoneBuilder(pb1);
pd.constructMobile();
PhoneBuilder *pb2 = new SmartApplePhoneBuilder;
cout<<" Creating Apple Phone ************"<<endl;
pd.setPhoneBuilder(pb2);
pd.constructMobile();
}
Now, the client or user is no longer involved in construction steps. It only needs to set or to direct to director what it want . Automatically Phone Director will direct the phone builder class to build desired product. Plus, the same construction process ConstructMobile will build several product variants.
Pros & Cons of Builder Design Pattern
Pros
- For creating complex product, the builder pattern is the best. This is because, all steps are inside the builder. And the user need not worry.
- User can build different product variant with same construction process.
- Loose coupling between construction and representation of the product.
Cons
- Need to create separate variant classes for each product, such as, basic phone, smart phone etc. It increases the code size.
- User is having only option of using existing product only.