Design patterns: Builder
The Builder Pattern is ideal when you need to construct complex objects in a clear and flexible way. It keeps the construction details separate from the final representation and improves code readability and maintainability.
Characteristics of the Builder pattern
- Separation of construction and representation: The Builder Pattern separates the process of constructing an object from its final representation, letting you create different kinds of objects with the same process.
- Step-by-step construction: Objects can be built incrementally, configuring the desired parameters over several steps. Each step can return the builder itself, enabling a fluent syntax.
- Immutability of the final object: The builder’s final result is often immutable, ensuring it can’t be modified after creation, which improves consistency and stability.
- Flexibility and extensibility: You can extend the builder to support new kinds of objects without modifying existing code. Adding new methods to configure extra parameters is straightforward.
- Ease of use: The Builder Pattern simplifies the creation of complex objects, hiding implementation details and reducing the number of constructors you need.
- Clarity and maintainability: Creating objects with a builder is clearer and easier to understand than using complex constructors, improving code readability and maintainability.
Example in PHP:
A common example of the Builder Pattern is constructing a Pizza object. You can have a pizza builder that lets you specify the toppings, the size and the baking options. You can add toppings or configure the pizza step by step and, once it’s done, get the final Pizza object.
class Pizza {
private $size;
private $cheese = false;
private $pepperoni = false;
private $mushrooms = false;
public function __construct($size) {
$this->size = $size;
}
public function __toString() {
$toppings = [];
if ($this->cheese) $toppings[] = "cheese";
if ($this->pepperoni) $toppings[] = "pepperoni";
if ($this->mushrooms) $toppings[] = "mushrooms";
return "Pizza: Size - {$this->size}, Toppings - " . implode(", ", $toppings);
}
public function addCheese() {
$this->cheese = true;
}
public function addPepperoni() {
$this->pepperoni = true;
}
public function addMushrooms() {
$this->mushrooms = true;
}
}
class PizzaBuilder {
private $size;
private $pizza;
public function __construct($size) {
$this->size = $size;
$this->pizza = new Pizza($this->size);
}
public function withCheese() {
$this->pizza->addCheese();
return $this;
}
public function withPepperoni() {
$this->pizza->addPepperoni();
return $this;
}
public function withMushrooms() {
$this->pizza->addMushrooms();
return $this;
}
public function build() {
return $this->pizza; // Returns the constructed Pizza object
}
}
// Create a builder for a "large" pizza
$pizzaBuilder = new PizzaBuilder("large");
// Add toppings and build the pizza
$pizza = $pizzaBuilder
->withCheese()
->withPepperoni()
->withMushrooms()
->build();
// Print the pizza
echo $pizza; // Output: Pizza: Size - large, Toppings - cheese, pepperoni, mushrooms