Jump to content

Builder

25% developed
From Wikibooks, open books for an open world

Bridge Computer Science Design Patterns
Builder
Chain of responsibility

The builder pattern is useful for avoiding a huge list of constructors for a class. Let's imagine a class that stores the mode of transport (of an employee for instance). Here is the constructor that takes a MetroLine object as a parameter:

modeOfTransport(MetroLine)

Now we need a constructor for someone who uses the car, the bus or the train:

new modeOfTransport(MetroLine)

new modeOfTransport()
new modeOfTransport(BusLine)

new modeOfTransport(Train)

For some of them, we need to indicate a travel allowance:

new modeOfTransport(MetroLine)

new modeOfTransport(MetroLine, Integer)
new modeOfTransport()
new modeOfTransport(Integer)
new modeOfTransport(BusLine)
new modeOfTransport(BusLine, Integer)
new modeOfTransport(Train)

new modeOfTransport(Train, Integer)

We have employees who use several modes of transport to go to work. However, we realize that the list of constructors is now becoming a mess. Each new parameter leads to an exponential duplication of constructors. If some parameters have the same type, it becomes very confusing. A solution to this issue would be to first build a fake object and then fill it by calling methods on it:

new modeOfTransport(MetroLine)

modeOfTransport.setMetroLine(MetroLine)
modeOfTransport.setCarTravel()
modeOfTransport.setBusLine(BusLine)
modeOfTransport.setTrain(Train)

modeOfTransport.setTravelAllowance(Integer)

The list of methods is no longer exponential but the state of the object may be inconsistent. A better solution would be to set all the parameters to an object of another class, a pre-constructor, and then pass this object to the constructor of ModeOfTransport:

modeOfTransportPreConstructor.setMetroLine(MetroLine)

modeOfTransportPreConstructor.setCarTravel()
modeOfTransportPreConstructor.setBusLine(BusLine)
modeOfTransportPreConstructor.setTrain(Train)
modeOfTransportPreConstructor.setTravelAllowance(Integer)

new modeOfTransport(ModeOfTransportPreConstructor)

This solution is even better. We only have a single valid ModeOfTransport object. However, the ModeOfTransport constructor can be called with a half-filled pre-constructor. So the pre-constructor should be a builder and should have a method that returns the ModeOfTransport object. This method will only return an object if the builder has been correctly filled, otherwise it returns null:

modeOfTransportBuilder.setMetroLine(MetroLine)

modeOfTransportBuilder.setCarTravel()
modeOfTransportBuilder.setBusLine(BusLine)
modeOfTransportBuilder.setTrain(Train)
modeOfTransportBuilder.setTravelAllowance(Integer)

modeOfTransport := modeOfTransportBuilder.getResult()

So the solution is to use a builder class. Let's see the structure of the code in an UML class diagram:

Builder Structure
Builder Structure
  • Builder: Abstract interface for creating objects (product).
  • Concrete Builder: Provides implementation for Builder. It is an object able to construct other objects. Constructs and assembles parts to build the objects.

The builder pattern can be used for objects that contain flat data (html code, SQL query, X.509 certificate...), that is to say data that can't be easily edited. This type of data can not be edited step by step and must be edited all at once. The best way to construct such an object is to use a builder class.

Examples

In Java, the StringBuffer and StringBuilder classes follow the builder design pattern. They are used to build String objects.

Cost

You can easily decide to use it. At worst, the pattern is useless.

Creation

Starting from a plain old class with a public constructor, implementing the design pattern is not very expensive. You can create the builder class alongside your code. Then you will have to remove the existing constructor calls to use the builder instead. The refactoring is hardly automatic.

Maintenance

This design pattern has only small drawbacks. It may lead to small redundancies between the class and the builder structures but the both class have usually different structures. However, it is expensive to convert to an abstract factory.

Removal

The refactoring is hardly automatic. It should be done manually.

Advices

  • Put the builder term in the name of the builder class to indicate the use of the pattern to the other developers.
  • Build your builder class as a fluent interface. It would increase the pattern interest.
  • If the target class contains flat data, your builder class can be constructed as a Composite that implements the Interpreter pattern.

Implementations

Implementation in Java

Building a car.

/**
 * Can have GPS, trip computer and a various number of seaters. Can be a city car, a sport car or a cabriolet.
 */
public class Car {
  /**
   * The description of the car.
   */
  private String description = null;

  /**
   * Construct and return the car.
   * @param aDescription The description of the car.
   */
  public Car(String aDescription) {
      description = aDescription;
    }
 
  /**
   * Print the car.
   * @return A flat representation.
   */
  public String toString() {
      return description;
    }
}
/**
 *
 */
public class CarBuilder {
  /**
   * Sport car.
   */
  private static final int SPORT_CAR = 1;

  /**
   * City car.
   */
  private static final int CITY_CAR = 2;

  /**
   * Cabriolet.
   */
  private static final int CABRIOLET = 3;

  /**
   * The type of the car.
   */
  private int carType;

  /**
   * True if the car has a trip computer.
   */
  private boolean hasTripComputer;

  /**
   * True if the car has a GPS.
   */
  private boolean hasGPS;

  /**
   * The number of seaters the car may have.
   */
  private int seaterNumber;

  /**
   * Construct and return the car.
   * @return a Car with the right options.
   */
  public Car getResult() {
      return new Car((carType == CITY_CAR) ? "A city car" : ((carType == SPORT_CAR) ? "A sport car" : "A cabriolet")
        + " with " + seaterNumber + " seaters"
        + (hasTripComputer ? " with a trip computer" : "")
        + (hasGPS ? " with a GPS" : "")
        + ".");
    }

  /**
   * Tell the builder the number of seaters.
   * @param number the number of seaters the car may have.
   */
  public void setSeaters(int number) {
      seaterNumber = number;
    }

  /**
   * Make the builder remember that the car is a city car.
   */
  public void setCityCar() {
      carType = CITY_CAR;
    }

  /**
   * Make the builder remember that the car is a cabriolet.
   */
  public void setCabriolet() {
      carType = CABRIOLET;
    }

  /**
   * Make the builder remember that the car is a sport car.
   */
  public void setSportCar() {
      carType = SPORT_CAR;
    }

  /**
   * Make the builder remember that the car has a trip computer.
   */
  public void setTripComputer() {
      hasTripComputer = true;
    }

  /**
   * Make the builder remember that the car has not a trip computer.
   */
  public void unsetTripComputer() {
      hasTripComputer = false;
    }

  /**
   * Make the builder remember that the car has a global positioning system.
   */
  public void setGPS() {
      hasGPS = true;
    }

  /**
   * Make the builder remember that the car has not a global positioning system.
   */
  public void unsetGPS() {
      hasGPS = false;
    }
}
/**
 * Construct a CarBuilder called carBuilder and build a car.
 */
public class Director {
  public static void main(String[] args) {
    CarBuilder carBuilder = new CarBuilder();
    carBuilder.setSeaters(2);
    carBuilder.setSportCar();
    carBuilder.setTripComputer();
    carBuilder.unsetGPS();
    Car car = carBuilder.getResult();

    System.out.println(car);
  }
}

It will produce:

A sport car with 2 seaters with a trip computer.

Building a pizza.

 /** "Product" */
class Pizza {
 private String dough = "";
 private String sauce = "";
 private String topping = "";

 public void setDough(final String dough) {
  this.dough = dough;
 }

 public void setSauce(final String sauce) {
  this.sauce = sauce;
 }

 public void setTopping(final String topping) {
  this.topping = topping;
 }
}
 /** "Abstract Builder" */
abstract class PizzaBuilder {
 protected Pizza pizza;

 public abstract void buildDough();
 public abstract void buildSauce();
 public abstract void buildTopping();

 public void createNewPizzaProduct() {
  this.pizza = new Pizza();
 }

 public Pizza getPizza() {
  return this.pizza;
 }
}
 /** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
 @Override public void buildDough() {
  this.pizza.setDough("cross");
 }

 @Override public void buildSauce() {
  this.pizza.setSauce("mild");
 }

 @Override public void buildTopping() {
  this.pizza.setTopping("ham+pineapple");
 }
}
 /** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
 @Override public void buildDough() {
  this.pizza.setDough("pan baked");
 }

 @Override public void buildSauce() {
  this.pizza.setSauce("hot");
 }

 @Override public void buildTopping() {
  this.pizza.setTopping("pepperoni+salami");
 }
}
 /** "Director" */
class Waiter {
 private PizzaBuilder pizzaBuilder;

 public void setPizzaBuilder(final PizzaBuilder pb) {
  this.pizzaBuilder = pb;
 }

 public Pizza getPizza() {
  return this.pizzaBuilder.getPizza();
 }

 public void constructPizza() {
  this.pizzaBuilder.createNewPizzaProduct();
  this.pizzaBuilder.buildDough();
  this.pizzaBuilder.buildSauce();
  this.pizzaBuilder.buildTopping();
 }
}
 /** A customer ordering a pizza. */
class BuilderExample {

 public static void main(final String[] args) {

  final Waiter waiter = new Waiter();

  final PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
  final PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

  waiter.setPizzaBuilder(hawaiianPizzaBuilder);
  waiter.constructPizza();

  final Pizza pizza = waiter.getPizza();

  waiter.setPizzaBuilder(spicyPizzaBuilder);
  waiter.constructPizza();

  final Pizza anotherPizza = waiter.getPizza();
 }
}
Implementation in C#

The Director assembles a bicycle instance in the example above, delegating the construction to a separate builder object that has been given to the Director by the Client.

/// <summary>
/// Represents a product created by the builder.
/// </summary>
public class Bicycle
{
    public Bicycle(string make, string model, string colour, int height)
    {
        Make = make;
        Model = model;
        Colour = colour;
        Height = height;
    }

    public string Make { get; set; }
    public string Model { get; set; }
    public int Height { get; set; }
    public string Colour { get; set; }
}

/// <summary>
/// The builder abstraction.
/// </summary>
public interface IBicycleBuilder
{
    Bicycle GetResult();

    string Colour { get; set; }
    int Height { get; set; }
}

/// <summary>
/// Concrete builder implementation.
/// </summary>
public class GTBuilder : IBicycleBuilder
{
    public Bicycle GetResult()
    {
        return Height == 29 ? new Bicycle("GT", "Avalanche", Colour, Height) : null;        
    }

    public string Colour { get; set; }
    public int Height { get; set; }
}

/// <summary>
/// The director.
/// </summary>
public class MountainBikeBuildDirector
{
    private IBicycleBuilder _builder;

    public MountainBikeBuildDirector(IBicycleBuilder builder) 
    {
        _builder = builder;
    }

    public void Construct()
    {
        _builder.Colour = "Red";
        _builder.Height = 29;
    }

    public Bicycle GetResult()
	{
		return this._builder.GetResult();
	}
}

public class Client
{
    public void DoSomethingWithBicycles()
    {
        var director = new MountainBikeBuildDirector(new GTBuilder());
        // Director controls the stepwise creation of product and returns the result.
        director.Construct();
        Bicycle myMountainBike = director.GetResult();
    }
}

Another example:

using System;

namespace BuilderPattern
{
  // Builder - abstract interface for creating objects (the product, in this case)
  abstract class PizzaBuilder
  {
    protected Pizza pizza;

    public Pizza GetPizza()
    {
      return pizza;
    }

    public void CreateNewPizzaProduct()
    {
      pizza = new Pizza();
    }

    public abstract void BuildDough();
    public abstract void BuildSauce();
    public abstract void BuildTopping();
  }
  // Concrete Builder - provides implementation for Builder; an object able to construct other objects.
  // Constructs and assembles parts to build the objects
  class HawaiianPizzaBuilder : PizzaBuilder
  {
    public override void BuildDough()
    {
      pizza.dough = "cross";
    }

    public override void BuildSauce()
    {
      pizza.sauce = "mild";
    }

    public override void BuildTopping()
    {
      pizza.topping = "ham+pineapple";
    }
  }
  // Concrete Builder - provides implementation for Builder; an object able to construct other objects.
  // Constructs and assembles parts to build the objects
  class SpicyPizzaBuilder : PizzaBuilder
  {
    public override void BuildDough()
    {
      pizza.dough = "pan baked";
    }

    public override void BuildSauce()
    {
      pizza.sauce = "hot";
    }

    public override void BuildTopping()
    {
      pizza.topping = "pepperoni + salami";
    }
  }
 
  // Director - responsible for managing the correct sequence of object creation.
  // Receives a Concrete Builder as a parameter and executes the necessary operations on it.
  class Cook
  {
    private PizzaBuilder _pizzaBuilder;

    public void SetPizzaBuilder(PizzaBuilder pb)
    {
      _pizzaBuilder = pb;
    }

    public Pizza GetPizza()
    {
      return _pizzaBuilder.GetPizza();
    }

    public void ConstructPizza()
    {
      _pizzaBuilder.CreateNewPizzaProduct();
      _pizzaBuilder.BuildDough();
      _pizzaBuilder.BuildSauce();
      _pizzaBuilder.BuildTopping();
    }
  }

  // Product - The final object that will be created by the Director using Builder
  public class Pizza
  {
    public string dough = string.Empty;
    public string sauce = string.Empty;
    public string topping = string.Empty;
  }

  class Program
  {
    static void Main(string[] args)
    {
      PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
      Cook cook = new Cook();
      cook.SetPizzaBuilder(hawaiianPizzaBuilder);
      cook.ConstructPizza();
      // create the product
      Pizza hawaiian = cook.GetPizza();

      PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();
      cook.SetPizzaBuilder(spicyPizzaBuilder);
      cook.ConstructPizza();
      // create another product
      Pizza spicy = cook.GetPizza();
    }
  }

}
Implementation in C++

This C++11 implementation is based on the pre C++98 implementation in the book.

#include <iostream>

enum Direction {North, South, East, West};

class MapSite {
public:
  virtual void enter() = 0;
  virtual ~MapSite() = default;
};

class Room : public MapSite {
public:
  Room() :roomNumber(0) {}
  Room(int n) :roomNumber(n) {}
  void setSide(Direction d, MapSite* ms) {
    std::cout << "Room::setSide " << d << ' ' << ms << '\n';
  }
  virtual void enter() {}
  Room(const Room&) = delete; // rule of three
  Room& operator=(const Room&) = delete;
private:
  int roomNumber;
};

class Wall : public MapSite {
public:
  Wall() {}
  virtual void enter() {}
};

class Door : public MapSite {
public:
  Door(Room* r1 = nullptr, Room* r2 = nullptr)
    :room1(r1), room2(r2) {}
  virtual void enter() {}
  Door(const Door&) = delete; // rule of three
  Door& operator=(const Door&) = delete;
private:
  Room* room1;
  Room* room2;
};

class Maze {
public:
  void addRoom(Room* r) {
    std::cout << "Maze::addRoom " << r << '\n';
  }
  Room* roomNo(int) const {
    return nullptr;
  }
};

class MazeBuilder {
public:
  virtual ~MazeBuilder() = default;
  virtual void buildMaze() = 0;
  virtual void buildRoom(int room) = 0;
  virtual void buildDoor(int roomFrom, int roomTo) = 0;

  virtual Maze* getMaze() {
    return nullptr;
  }
protected:
  MazeBuilder() = default;
};

// If createMaze is passed an object that can create a new maze in its entirety using operations for adding rooms, doors, and walls to the maze it builds, then you can use inheritance to change parts of the maze or the way the maze is built. This is an example of the Builder (110) pattern.

class MazeGame {
public:
  Maze* createMaze(MazeBuilder& builder) {
    builder.buildMaze();
    builder.buildRoom(1);
    builder.buildRoom(2);
    builder.buildDoor(1, 2);
    return builder.getMaze();
  }
  Maze* CreateComplexMaze(MazeBuilder& builder) {
    builder.buildRoom(1);
    // ...
    builder.buildRoom(1001);
    return builder.getMaze();
  }
};

class StandardMazeBuilder : public MazeBuilder {
public:
  StandardMazeBuilder() :currentMaze(nullptr) {}
  virtual void buildMaze() {
    currentMaze = new Maze;
  }
  virtual void buildRoom(int n) {
    if (!currentMaze->roomNo(n)) {
      Room* room = new Room(n);
      currentMaze->addRoom(room);
      room->setSide(North, new Wall);
      room->setSide(South, new Wall);
      room->setSide(East, new Wall);
      room->setSide(West, new Wall);
    }
  }
  virtual void buildDoor(int n1, int n2) {
    Room* r1 = currentMaze->roomNo(n1);
    Room* r2 = currentMaze->roomNo(n2);
    Door* d = new Door(r1, r2);
    r1->setSide(commonWall(r1,r2), d);
    r2->setSide(commonWall(r2,r1), d);
  }
  virtual Maze* getMaze() {
    return currentMaze;
  }
  StandardMazeBuilder(const StandardMazeBuilder&) = delete; // rule of three
  StandardMazeBuilder& operator=(const StandardMazeBuilder&) = delete;
private:
  Direction commonWall(Room*, Room*) {
    return North;
  }
  Maze* currentMaze;
};

int main() {
  MazeGame game;
  StandardMazeBuilder builder;
  game.createMaze(builder);
  builder.getMaze();
}

The program output is like:

Maze::addRoom 0x2145ed0
Room::setSide 0 0x2146300
Room::setSide 1 0x2146320
Room::setSide 2 0x2146340
Room::setSide 3 0x2146360
Maze::addRoom 0x2146380
Room::setSide 0 0x21463a0
Room::setSide 1 0x21463c0
Room::setSide 2 0x21463e0
Room::setSide 3 0x2146400
Room::setSide 0 0x2146420
Room::setSide 0 0x2146420

Another example:

#include <string>
#include <iostream>
using namespace std;
 
// "Product"
class Pizza {
public:
        void dough(const string& dough) {
                dough_ = dough;
        }
 
        void sauce(const string& sauce) {
                sauce_ = sauce;
        }
 
        void topping(const string& topping) {
                topping_ = topping;
        }
 
        void open() const {
                cout << "Pizza with " << dough_ << " dough, " << sauce_ << " sauce and "
                        << topping_ << " topping. Mmm." << endl;
        }
 
private:
        string dough_;
        string sauce_;
        string topping_;
};
 
// "Abstract Builder"
class PizzaBuilder {
public:
       // Chinmay Mandal : This default constructor may not be required here
        PizzaBuilder()
        {
           // Chinmay Mandal : Wrong syntax
           // pizza_ = new Pizza;
        }
        const Pizza& pizza() {
                return pizza_;
        }
 
        virtual void buildDough() = 0;
        virtual void buildSauce() = 0;
        virtual void buildTopping() = 0;
 
protected:
        Pizza pizza_;
};
 
class HawaiianPizzaBuilder : public PizzaBuilder {
public:
        void buildDough() {
                pizza_.dough("cross");
        }
 
        void buildSauce() {
                pizza_.sauce("mild");
        }
 
        void buildTopping() {
                pizza_.topping("ham+pineapple");
        }
};
 
class SpicyPizzaBuilder : public PizzaBuilder {
public:
        void buildDough() {
                pizza_.dough("pan baked");
        }
 
        void buildSauce() {
                pizza_.sauce("hot");
        }
 
        void buildTopping() {
                pizza_.topping("pepperoni+salami");
        }
};
 
class Cook {
public:
        Cook()
                : pizzaBuilder_(NULL/*nullptr*/)//Chinmay Mandal : nullptr replaced with NULL.
        {       }
 
        ~Cook() {
                if (pizzaBuilder_)
                        delete pizzaBuilder_;
        }
 
        void pizzaBuilder(PizzaBuilder* pizzaBuilder) {
                if (pizzaBuilder_)
                        delete pizzaBuilder_;
 
                pizzaBuilder_ = pizzaBuilder;
        }
 
        const Pizza& getPizza() {
                return pizzaBuilder_->pizza();
        }
 
        void constructPizza() {
                pizzaBuilder_->buildDough();
                pizzaBuilder_->buildSauce();
                pizzaBuilder_->buildTopping();
        }
 
private:
        PizzaBuilder* pizzaBuilder_;
};
 
int main() {
        Cook cook;
        cook.pizzaBuilder(new HawaiianPizzaBuilder);
        cook.constructPizza();
 
        Pizza hawaiian = cook.getPizza();
        hawaiian.open();
 
        cook.pizzaBuilder(new SpicyPizzaBuilder);
        cook.constructPizza();
 
        Pizza spicy = cook.getPizza();
        spicy.open();
}
Implementation in PHP
<?php
/** "Product" */
class Pizza {

    protected $dough;
    protected $sauce;
    protected $topping;

    public function setDough($dough) {
        $this->dough = $dough;
    }

    public function setSauce($sauce) {
        $this->sauce = $sauce;
    }

    public function setTopping($topping) {
        $this->topping = $topping;
    }

    public function showIngredients() {
        echo "Dough   : ".$this->dough."<br/>";
        echo "Sauce   : ".$this->sauce."<br/>";
        echo "Topping : ".$this->topping."<br/>";
    }
}

/** "Abstract Builder" */
abstract class PizzaBuilder {

    protected $pizza;

    public function getPizza() {
        return $this->pizza;
    }

    public function createNewPizzaProduct() {
        $this->pizza = new Pizza();
    }

    public abstract function buildDough();
    public abstract function buildSauce();
    public abstract function buildTopping();
}

/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
    public function buildDough() {
        $this->pizza->setDough("cross");
    }

    public function buildSauce() {
        $this->pizza->setSauce("mild");
    }

    public function buildTopping() {
        $this->pizza->setTopping("ham + pineapple");
    }
}

/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {

    public function buildDough() {
        $this->pizza->setDough("pan baked");
    }

    public function buildSauce() {
        $this->pizza->setSauce("hot");
    }

    public function buildTopping() {
        $this->pizza->setTopping("pepperoni + salami");
    }
}

/** "Director" */
class Waiter {

    protected $pizzaBuilder;

    public function setPizzaBuilder(PizzaBuilder $pizzaBuilder) {
        $this->pizzaBuilder = $pizzaBuilder;
    }

    public function getPizza() {
        return $this->pizzaBuilder->getPizza();
    }

    public function constructPizza() {
        $this->pizzaBuilder->createNewPizzaProduct();
        $this->pizzaBuilder->buildDough();
        $this->pizzaBuilder->buildSauce();
        $this->pizzaBuilder->buildTopping();
    }
}

class Tester {

    public static function main() {

        $oWaiter               = new Waiter();
        $oHawaiianPizzaBuilder = new HawaiianPizzaBuilder();
        $oSpicyPizzaBuilder    = new SpicyPizzaBuilder();

        $oWaiter->setPizzaBuilder($oHawaiianPizzaBuilder);
        $oWaiter->constructPizza();

        $pizza = $oWaiter->getPizza();
        $pizza->showIngredients();

        echo "<br/>";

        $oWaiter->setPizzaBuilder($oSpicyPizzaBuilder);
        $oWaiter->constructPizza();

        $pizza = $oWaiter->getPizza();
        $pizza->showIngredients();
    }
}

Tester::main();

output :

   Dough : cross
   Sauce : mild
   Topping : ham + pineapple
   Dough : pan baked
   Sauce : hot
   Topping : pepperoni + salami
Implementation in Ruby
# Product
class Pizza
  attr_accessor :dough, :sauce, :topping
end

# Abstract Builder
class PizzaBuilder
  def get_pizza
    @pizza
  end

  def create_new_pizza_product
    @pizza = Pizza.new
  end

  def build_dough; end
  def build_sauce; end
  def build_topping; end

end

# ConcreteBuilder
class HawaiianPizzaBuilder < PizzaBuilder
  def build_dough
    @pizza.dough = 'cross'
  end
 
  def build_sauce
    @pizza.sauce = 'mild'
  end

  def build_topping
    @pizza.topping = 'ham+pineapple'
  end
end

# ConcreteBuilder
class SpicyPizzaBuilder < PizzaBuilder
  def build_dough
    @pizza.dough = 'pan baked'
  end

  def build_sauce
    @pizza.sauce = 'hot'
  end

  def build_topping
    @pizza.topping = 'pepperoni+salami'
  end
end

# Director
class Waiter
  attr_accessor :pizza_builder

  def get_pizza
    pizza_builder.get_pizza
  end

  def construct_pizza
    pizza_builder.create_new_pizza_product
    pizza_builder.build_dough
    pizza_builder.build_sauce
    pizza_builder.build_topping
  end
end
 
# A customer ordering a pizza.
class BuilderExample
  def main(args = [])
    waiter = Waiter.new
    hawaiian_pizza_builder = HawaiianPizzaBuilder.new
    spicy_pizza_builder = SpicyPizzaBuilder.new

    waiter.pizza_builder = hawaiian_pizza_builder
    waiter.construct_pizza

    pizza = waiter.get_pizza
  end
end

puts BuilderExample.new.main.inspect
Implementation in Python
class Animal:
    """
    Abstract Animal
    """
    legs = 0
    tail = False
    roar = ''

class Mutator:
    """
    Mutator
    """
    def mutate(self):
        self.animal = Animal()

class Cat(Mutator):
    """
    Cat
    """
    def create_legs(self):
        self.animal.legs = 4
 
    def create_tail(self):
        self.animal.tail = True

    def create_roar(self):
        self.animal.roar = 'meowww!'

class Dog(Mutator):
    """
    Dog
    """
    def create_legs(self):
        self.animal.legs = 4

    def create_tail(self):
        self.animal.tail = True

    def create_roar(self):
        self.animal.roar = 'woffff!'

class AnimalOwner:
    """
    Farm owner
    """
    __mutator = ''
    def set_animal(self, mutator):
        self.__mutator = mutator

    def create_an_animal_for_me(self):
        self.__mutator.mutate()
        self.__mutator.create_legs()
        self.__mutator.create_tail()
        self.__mutator.create_roar()

    def get_animal(self):
        return self.__mutator.animal

c = Cat()
d = Dog()
ao = AnimalOwner()
ao.set_animal(c)
ao.create_an_animal_for_me()
animal = ao.get_animal()
print(animal.roar)  # meowww!
Implementation in Delphi
program Builder;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
(*Product - final object that will be created by Director using Builder*)
  TPizza = class
    fDough: string;
    fSauce: string;
    fTopping: string;
    procedure Open;
  end;

  (*Builder - abstract class as interface for creating  objects -> product in this case*)
  TPizzaBuilder = class abstract
  protected
    fPizza: TPizza;
    public
    function GetPizza: TPizza;
    procedure CreateNewPizzaProduct;
    procedure BuildDough; virtual; abstract;
    procedure BuildSauce; virtual; abstract;
    procedure BuildTopping; virtual; abstract;
  end;

  (*concrete builder - provides implementation for Builder *)
  (*an object able to construct other objects.*)
  THawaiianPizzaBuilder = class(TPizzaBuilder)
    public
      procedure BuildDough; override;
      procedure BuildSauce; override;
      procedure BuildTopping; override;
  end;

  (*concrete builder = provides implenentation for Builder*)
  (*an object able to construct other objects.*)
  TSpicyPizzaBuilder = class(TPizzaBuilder)
    public
      procedure BuildDough; override;
      procedure BuildSauce; override;
      procedure BuildTopping; override;
  end;

  (*Director - responsible for managing the correct sequence of object creation.*)
  (*Receives a Concrete Builder as a parameter and executes the necessary operations on it.*)
  TCook = class
  protected
    fPizzaBuilder: TPizzaBuilder;
    public
      procedure SetPizzaBuilder(pb: TPizzaBuilder);
      function GetPizza: TPizza;
      procedure ConstructPizza;
  end;

{ THawaiianPizzaBuilder }

procedure THawaiianPizzaBuilder.BuildDough;
begin
  fPizza.fDough:= 'cross';
end;

procedure THawaiianPizzaBuilder.BuildSauce;
begin
  fPizza.fSauce:= 'mild';
end;

procedure THawaiianPizzaBuilder.BuildTopping;
begin
  fPizza.fTopping:= 'ham + pineapple';
end;

{ TSpicyPizzaBuilder }

procedure TSpicyPizzaBuilder.BuildDough;
begin
  fPizza.fDough:= 'pan baked';
end;

procedure TSpicyPizzaBuilder.BuildSauce;
begin
  fPizza.fSauce:= 'hot';
end;

procedure TSpicyPizzaBuilder.BuildTopping;
begin
  fPizza.fTopping:= 'pepperoni + salami';
end;

{ TCook }

procedure TCook.ConstructPizza;
begin
  fPizzaBuilder.CreateNewPizzaProduct;
  fPizzaBuilder.BuildDough;
  fPizzaBuilder.BuildSauce;
  fPizzaBuilder.BuildTopping;
end;

function TCook.GetPizza: TPizza;
begin
  Result:= fPizzaBuilder.GetPizza;
end;

procedure TCook.SetPizzaBuilder(pb: TPizzaBuilder);
begin
   fPizzaBuilder:= pb;
end;

{ TPizzaBuilder }

procedure TPizzaBuilder.CreateNewPizzaProduct;
begin
  fPizza:= TPizza.Create;
end;

function TPizzaBuilder.GetPizza: TPizza;
begin
   Result:= fPizza;
end;

{ TPizza }

procedure TPizza.Open;
begin
  WriteLn('Pizza with: ' + fDough + ' dough, ' +
  fSauce +' souce and '+fTopping +' topping. Mmm.');
end;

var
  cook: TCook;
  hawaiian, spicy: TPizza;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }

    cook:= TCook.Create;
    cook.SetPizzaBuilder(THawaiianPizzaBuilder.Create);
    cook.ConstructPizza;

    WriteLn('(* create the product *)');

    hawaiian:= cook.GetPizza;
    hawaiian.Open;

    WriteLn(#13#10+'(* create another product *)');

    cook.SetPizzaBuilder(TSpicyPizzaBuilder.Create);
    cook.ConstructPizza;

    spicy:= cook.GetPizza;
    spicy.Open;

    WriteLn(#13#10+'Press any key to continue...');
    ReadLn;

    spicy.Free;
    hawaiian.Free;
    cook.Free;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.


Clipboard

To do:
Add more examples of use.


Bridge Computer Science Design Patterns
Builder
Chain of responsibility


You have questions about this page?
Ask it here:


Create a new page on this book: