Skip to content

Instantly share code, notes, and snippets.

@pazdera
Created August 2, 2011 20:33
Show Gist options
  • Save pazdera/1121152 to your computer and use it in GitHub Desktop.
Save pazdera/1121152 to your computer and use it in GitHub Desktop.
Example of `builder' design pattern in C++
/*
* Example of `builder' design pattern.
* Copyright (C) 2011 Radek Pazdera
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <string>
/* Car parts */
class Wheel
{
public:
int size;
};
class Engine
{
public:
int horsepower;
};
class Body
{
public:
std::string shape;
};
/* Final product -- a car */
class Car
{
public:
Wheel* wheels[4];
Engine* engine;
Body* body;
void specifications()
{
std::cout << "body:" << body->shape << std::endl;
std::cout << "engine horsepower:" << engine->horsepower << std::endl;
std::cout << "tire size:" << wheels[0]->size << "'" << std::endl;
}
};
/* Builder is responsible for constructing the smaller parts */
class Builder
{
public:
virtual Wheel* getWheel() = 0;
virtual Engine* getEngine() = 0;
virtual Body* getBody() = 0;
};
/* Director is responsible for the whole process */
class Director
{
Builder* builder;
public:
void setBuilder(Builder* newBuilder)
{
builder = newBuilder;
}
Car* getCar()
{
Car* car = new Car();
car->body = builder->getBody();
car->engine = builder->getEngine();
car->wheels[0] = builder->getWheel();
car->wheels[1] = builder->getWheel();
car->wheels[2] = builder->getWheel();
car->wheels[3] = builder->getWheel();
return car;
}
};
/* Concrete Builder for Jeep SUV cars */
class JeepBuilder : public Builder
{
public:
Wheel* getWheel()
{
Wheel* wheel = new Wheel();
wheel->size = 22;
return wheel;
}
Engine* getEngine()
{
Engine* engine = new Engine();
engine->horsepower = 400;
return engine;
}
Body* getBody()
{
Body* body = new Body();
body->shape = "SUV";
}
};
/* Concrete builder for Nissan family cars */
class NissanBuilder : public Builder
{
public:
Wheel* getWheel()
{
Wheel* wheel = new Wheel();
wheel->size = 16;
return wheel;
}
Engine* getEngine()
{
Engine* engine = new Engine();
engine->horsepower = 85;
return engine;
}
Body* getBody()
{
Body* body = new Body();
body->shape = "hatchback";
}
};
int main()
{
Car* car; // Final product
/* A director who controls the process */
Director director;
/* Concrete builders */
JeepBuilder jeepBuilder;
NissanBuilder nissanBuilder;
/* Build a Jeep */
std::cout << "Jeep" << std::endl;
director.setBuilder(&jeepBuilder); // using JeepBuilder instance
car = director.getCar();
car->specifications();
std::cout << std::endl;
/* Build a Nissan */
std::cout << "Nissan" << std::endl;
director.setBuilder(&nissanBuilder); // using NissanBuilder instance
car = director.getCar();
car->specifications();
return 0;
}
@drvirens
Copy link

good example. thanks.

@drvirens
Copy link

hi i know you are still working on this example, but there is a small typo in getBody() function: it should return body.
Body* getBody()
{
Body* body = new Body();
body->shape = "hatchback";
return body; // <---- missing
}

@sujeet05
Copy link

As i know in Builder pattern , instead of director builder is responsible to return the product in above code Director is returning which is wrong - correct me if i am wrong - http://www.vincehuston.org/dp/builder.html

@didihe1988
Copy link

gelivable

@ccostel
Copy link

ccostel commented Jan 8, 2017

Hey!

Thanks for this simple yet very useful gist. I have a follow up question though.

How would one implement this code to build a "Car" with optional configurations without writing dedicated builders?

Scenario 1
Build a car with 3 wheels, no body and no engine.

Scenario 2
Build a car with 2 wheels, with a body and an engine.

Scenario 3
Build a car with 1 wheel, no body and no engine.

Scenrion N
Some other random combination.

And let's imagine the "Car" object requires at least one wheel to be built.

I have stumbled upon a blog post that mentions a state machine approach but it still seems a bit messy to me.

The post: https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/

@yuliamsky
Copy link

I would suggest not to use raw pointers, use std::shared_ptr or std::unique_ptr instead.

@Prerit-Jain-0
Copy link

Very simple and good example to understand the builder design pattern..... thanks a lot...

@shadaflorida
Copy link

Thanks for this!

@beizhengren
Copy link

beizhengren commented May 11, 2021

I would suggest not to use raw pointers, use std::shared_ptr or std::unique_ptr instead.

how to realize by std::unique_ptr, please? @yuliamsky

@ariefroim
Copy link

hi i know you are still working on this example, but there is a small typo in getBody() function: it should return body.
Body* getBody()
{
Body* body = new Body();
body->shape = "hatchback";
return body; // <---- missing
}

The same "typo" exists in the JeepBuilder - getBody method. Enjoy!

@fjrg76-com
Copy link

  1. Don't use the Director object, let your code itself (the client) to call the parts your car needs.
  2. Let the classes Wheel, Engine and Body to return a reference so you can chain the calls so you gain (in the client's side) control of what you're creting.

(Your question has been addressed in the book "Design Patterns in Modern C++20: Reusable Approaches for Object-Oriented Software Design" by Dmitri Nesteruk. Ed. Apress.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment