Builder design pattern.

Problem statement –

How will you make sure that your code is constructing/building mature/full object? Or how you can restrict the object creation process such that it follows a well-defined way to build any complex object.

Background –

I am talking about a design pattern that has come from the automobile industry. When you are making something (i.e., like Toyota is making a car). How can you make sure all its products are the best quality products?

So the question is - whenever any company builds products, how it makes sure the product's quality?

They standardize the construction process. They believe that if the construction of the object is proper (standardize construction process). Then the result is as per our expectations (with best quality).

The main rule here is - "once we define how we construct the object, then we can use the same standardize process for different objects." 

For example – Once Toyota understood how to make the best car, it uses the same best quality creation process for its different model (technically in software, different objects).

Why we need builder pattern –

We want to standardize the construction process of a complex object. Use the same standardize construction process for different classes to make sure mature/full object creation.

When we deal with a complex object, which has many composite objects init and need to follow a particular flow to create those objects. It is better to hide such complexity of creating that object behind some creational design pattern. No need for the client to insert complex code to create an object.

Sometimes We don't want the client to know all internal of our library or our implementation. And sometimes, though we don't have any issues, other codes know about our modules, but we want to hide the complexity of creating that object. 

About builder design pattern –

Builder is all about control. We are controlling the construction process and restricting to follow specific rules.

Structure –


Note: My suggestion for readers is first to read the example and understand Builder, then come back and learned about Builder Structure Blocks


  1. Builder – This is the interface; which control the creation process. It has a set of pure virtual functions. In concrete implementation, you have to override those pure virtual function.
  2. ConcreteBuilder – Here, we have our implementation based on different classes. Define the functions which we have to override from its base class mandatorily.
  3. Product - This is the real class for which we want to create objects. 
  4. Director – It acts like a client; who ask to create the object through the builder interface.

Example –

So here I am trying to create an interface which will make sure that you follow a specific process mandatory while creating it.





Note: for more clear picture, please click on the image.

CPP code -


 /*
 * Builder design pattern.
 * example # - 1.
 */

#include<iostream>
#include<string>
using namespace std;

//-------------------------------------------------------------------------------------------------------------
class vegetable {

private:
 string m_saltQty;
 string m_ChiliQty;
 string m_OilQty;
 string m_BlackPepperQty;
 string m_CuminSeedsQty;
public:
 void addSaltToVegetable(const string& saltQty) {
  m_saltQty = saltQty;
 }
 void addChiliToVegetable(const string& ChiliQty) {
  m_ChiliQty = ChiliQty;
 }
 void addOilToVegetable(const string& OilQty) {
  m_OilQty = OilQty;
 }
 void addBlackPepperToVegetable(const string& BlackPepperQty) {
  m_BlackPepperQty = BlackPepperQty;
 }
 void addCuminSeedsToVegetable(const string& CuminSeedsQty) {
  m_CuminSeedsQty = CuminSeedsQty;
 }
 void make() {
  cout<<"m_saltQty = "<<m_saltQty <<endl
   <<"m_ChiliQty = "<<m_ChiliQty <<endl
   <<"m_OilQty = "<<m_OilQty <<endl
   <<"m_BlackPepperQty = "<<m_BlackPepperQty <<endl
   <<"m_CuminSeedsQty = " <<m_CuminSeedsQty <<endl;
 }
};

//-------------------------------------------------------------------------------------------------------------
class vegetableBuilder {
protected:
 vegetable *m_vegetable;
public:
 vegetable* getVegetable() {
  return m_vegetable;
 }
 void createNewVegetable() {
  m_vegetable = new vegetable();
 }
 virtual ~vegetableBuilder();
 virtual void addSalt() = 0;
 virtual void addChili() = 0;
 virtual void addOil() = 0;
 virtual void addBlackPepper() = 0;
 virtual void addCuminSeeds() = 0;
};

//-------------------------------------------------------------------------------------------------------------
class bhindiMasala:public vegetableBuilder {

public:
 virtual ~bhindiMasala() {}
 void addSalt() {
  m_vegetable->addSaltToVegetable("half spoon");
 }
 void addChili() {
  m_vegetable->addChiliToVegetable("half spoon");
 }
 void addOil() {
  m_vegetable->addOilToVegetable("2 ml");
 }
 void addBlackPepper() {
  m_vegetable->addBlackPepperToVegetable("0.5 G");
 }
 void addCuminSeeds() {
  m_vegetable->addCuminSeedsToVegetable("0.5 G");
 }
};
//-------------------------------------------------------------------------------------------------------------
class matarPaneer:public vegetableBuilder {

public:
 virtual ~matarPaneer() {}
 void addSalt() {
  m_vegetable->addSaltToVegetable("half spoon");
 }
 void addChili() {
  m_vegetable->addChiliToVegetable("half spoon");
 }
 void addOil() {
  m_vegetable->addOilToVegetable("2 ml");
 }
 void addBlackPepper() {
  m_vegetable->addBlackPepperToVegetable("0.5 G");
 }
 void addCuminSeeds() {
  m_vegetable->addCuminSeedsToVegetable("0.5 G");
 }
};
//-------------------------------------------------------------------------------------------------------------
class aluGobi:public vegetableBuilder {

 public:
 virtual ~aluGobi() {}
 void addSalt() {
  m_vegetable->addSaltToVegetable("half spoon");
 }
 void addChili() {
  m_vegetable->addChiliToVegetable("half spoon");
 }
 void addOil() {
  m_vegetable->addOilToVegetable("2 ml");
 }
 void addBlackPepper() {
  m_vegetable->addBlackPepperToVegetable("0.5 G");
 }
 void addCuminSeeds() {
  m_vegetable->addCuminSeedsToVegetable("0.5 G");
 }
};
//-------------------------------------------------------------------------------------------------------------
class karelaFry:public vegetableBuilder {

 
 public:
 virtual ~karelaFry() {}
 void addSalt() {
  m_vegetable->addSaltToVegetable("half spoon");
 }
 void addChili() {
  m_vegetable->addChiliToVegetable("half spoon");
 }
 void addOil() {
  m_vegetable->addOilToVegetable("2 ml");
 }
 void addBlackPepper() {
  m_vegetable->addBlackPepperToVegetable("0.5 G");
 }
 void addCuminSeeds() {
  m_vegetable->addCuminSeedsToVegetable("0.5 G");
 }
};
//-------------------------------------------------------------------------------------------------------------
class palakPaneer:public vegetableBuilder {

public:
 virtual ~palakPaneer() {}
 void addSalt() {
  m_vegetable->addSaltToVegetable("half spoon");
 }
 void addChili() {
  m_vegetable->addChiliToVegetable("half spoon");
 }
 void addOil() {
  m_vegetable->addOilToVegetable("2 ml");
 }
 void addBlackPepper() {
  m_vegetable->addBlackPepperToVegetable("0.5 G");
 }
 void addCuminSeeds() {
  m_vegetable->addCuminSeedsToVegetable("0.5 G");
 }
};
//-------------------------------------------------------------------------------------------------------------
class cook {
private:
 vegetableBuilder *p_vegetableBuilder;
public:
 void setvegetableBuilder(vegetableBuilder * input){
  p_vegetableBuilder = input;
 }
 vegetable * getvegetable() {
  return p_vegetableBuilder->getVegetable();
 }
 void constructVegetable() {
  p_vegetableBuilder->createNewVegetable();
  p_vegetableBuilder->addSalt();
  p_vegetableBuilder->addChili();
  p_vegetableBuilder->addBlackPepper();
  p_vegetableBuilder->addCuminSeeds();
 }
};
//-------------------------------------------------------------------------------------------------------------
int main(int argc, char **argv) {

 cook l_cook;
 vegetableBuilder * p_bhindiMasala= new bhindiMasala();
 vegetableBuilder * p_aluGobi= new aluGobi();
 vegetableBuilder * p_karelaFry= new karelaFry();
 vegetableBuilder * p_palakPaneer= new palakPaneer();

 l_cook.setvegetableBuilder(p_bhindiMasala);
 l_cook.constructVegetable();

 vegetable *ptr1 = l_cook.getvegetable();
 ptr1->make();

 l_cook.setvegetableBuilder(p_aluGobi);
 l_cook.constructVegetable();

 vegetable *ptr2 = l_cook.getvegetable();
 ptr2->make();

 l_cook.setvegetableBuilder(p_karelaFry);
 l_cook.constructVegetable();

 vegetable *ptr3 = l_cook.getvegetable();
 ptr3->make();

 l_cook.setvegetableBuilder(p_palakPaneer);
 l_cook.constructVegetable();

 vegetable *ptr4 = l_cook.getvegetable();
 ptr4->make();

 delete p_bhindiMasala;
 delete p_aluGobi;
 delete p_karelaFry;
 delete p_palakPaneer;
 delete ptr1;
 delete ptr2;
 delete ptr3;
 delete ptr4;

 return 0;
}


Thanks for reading it. To learn more about design patterns and basic design principles, please see my web page.

Comments

  1. Very nicely put..especially theory..Example is good too but can be improved for better clarity. Thanks for sharing!

    ReplyDelete

Post a Comment

Popular posts from this blog

Non-virtual interface idiom (NVI)

Factory method design pattern for beginners.

Architectural patterns => Mud to structure => layers.