Pseudocode[edit]
We have a Car class. The problem is that a car has many options. The combination of each option would lead to a huge list of constructors for this class. So we will create a builder class, CarBuilder. We will send to the CarBuilder each car option step by step and then construct the final car with the right options:
class Car is Can have GPS, trip computer and various numbers of seats. Can be a city car, a sports car, or a cabriolet. class CarBuilder is method getResult is output: a Car with the right options Construct and return the car. method setSeats(number) is input: the number of seats the car may have. Tell the builder the number of seats. method setCityCar is Make the builder remember that the car is a city car. method setCabriolet is Make the builder remember that the car is a cabriolet. method setSportsCar is Make the builder remember that the car is a sports car. method setTripComputer is Make the builder remember that the car has a trip computer. method unsetTripComputer is Make the builder remember that the car does not have a trip computer. method setGPS is Make the builder remember that the car has a global positioning system. method unsetGPS is Make the builder remember that the car does not have a global positioning system. Construct a CarBuilder called carBuilder carBuilder.setSeats(2) carBuilder.setSportsCar carBuilder.setTripComputer carBuilder.unsetGPS car := carBuilder.getResult
Of course one could dispense with Builder and just do this:
car = new Car; car.seats = 2; car.type = CarType.SportsCar; car.setTripComputer; car.unsetGPS; car.isValid;
So this indicates that the Builder pattern is more than just a means to limit constructor proliferation. It removes what could be a complex building process from being the responsibility of the user of the object that is built. It also allows for inserting new implementations of how an object is built without disturbing the client code.
C# Example[edit]
//Represents a product created by the builder public class Car { public Car { } public int Wheels { get; set; } public string Colour { get; set; } } //The builder abstraction public interface ICarBuilder { // Adding NotNull attribute to prevent null input argument void SetColour([NotNull]string colour); // Adding NotNull attribute to prevent null input argument void SetWheels([NotNull]int count); Car GetResult; } //Concrete builder implementation public class CarBuilder : ICarBuilder { private Car _car; public CarBuilder { this._car = new Car; } public void SetColour(string colour) { this._car.Colour = colour; } public void SetWheels(int count) { this._car.Wheels = count; } public Car GetResult { return this._car; } } //The director public class CarBuildDirector { public Car Construct { CarBuilder builder = new CarBuilder; builder.SetColour("Red"); builder.SetWheels(4); return builder.GetResult; } }
The Director assembles a car instance in the example above, delegating the construction to a separate builder object.
C++ Example[edit]
/ Product declarations and inline impl. (possibly Product.h) / class Product{ public: // use this class to construct Product class Builder; private: // variables in need of initialization to make valid object int i; float f; char c; // Only one simple constructor - rest is handled by Builder Product( const int i, const float f, const char c ) : i(i), f(f), c(c){} public: // Product specific functionality void print; void doSomething; void doSomethingElse; }; class Product::Builder{ private: // variables needed for construction of object of Product class int i; float f; char c; public: // default values for variables static const int defaultI = 1; static const float defaultF = 3.1415f; static const char defaultC = 'a'; // create Builder with default values assigned // (in C++11 they can be simply assigned above on declaration instead) Builder : i( defaultI ), f( defaultF ), c( defaultC ){} // sets custom values for Product creation // returns Builder for shorthand inline usage (same way as cout i = i; return *this; } Builder& setF( const float f ){ this->f = f; return *this; } Builder& setC( const char c ){ this->c = c; return *this; } // prepare specific frequently desired Product // returns Builder for shorthand inline usage (same way as cout i = 42; this->f = -1.0f/12.0f; this->c = '@'; return *this; } // produce desired Product Product build{ // here optionaly check variable consistency // and also if Product is buildable from given information return Product( this->i, this->f, this->c ); } };
/ Product implementation (possibly Product.cpp) / #include void Product::print{ using namespace std; cout < "Product internals dump:" < endl; cout < "i: " < this->i < endl; cout < "f: " < this->f < endl; cout < "c: " < this->c < endl; } void Product::doSomething{} void Product::doSomethingElse{}