What is the builder pattern?

The builder pattern is a type of design pattern template for solving programming tasks in object-oriented programming. Builder patterns make programming easier for developers, because not every step that occurs repeatedly has to be re-designed as a program routine.

Instead, an established solution can be used. The software elements are based on the book ‘Design Pattern: Elements of Reusable Object-Oriented Software’ published in 1994 by four US software developers – known as the Gang of Four, or GoF for short. Our guide introduces you to the essential aspects of the builder design pattern including a practical example.

The builder pattern in detail

The builder pattern belongs to the group of construction patterns within design patterns. It improves both the security of constructing and the readability of the program code. The aim of the builder design pattern is to create an object without known constructors, but with an auxiliary class.

Quote

‘Separate the construction of a complex object from its representation so that the same construction process can create different representations.’

- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (= ‘Gang of Four’)

Source: Design Patterns: Elements of Reusable Object-Oriented Software 1. Edition, Publisher: Addison-Wesley Professional; 1. Edition (10th November 1994)

A builder design pattern distinguishes between four actors:

  • Director: This actor constructs the complex object using the interface of the builder. They are aware of the sequence requirements of the builder. With the director, the construction of an object is decoupled from the customer (‘client’).
  • Builder: Provides an interface for creating the components of a complex object (or product).
  • Specific builder: This actor creates the parts of the complex object and defines (and manages) the representation of the object, and maintains an interface for the output of the object.
  • Product: The result of the ‘activity’ of the builder pattern, i.e. the complex object to be constructed.

The director oversees the decisive process of the builder pattern: the separation of the creation of an object/product from the client.

UML presentation of the builder pattern

The Unified Modeling Language, in short UML, is useful to graphically represent the programming processes. The graphic shows that the builder pattern consists of several objects that interact with one another.

Pros and cons of the design pattern

Here’s a look at the pros and cons.

Pros of builder pattern

The construction and representation (output) are incorporated separately. The internal representations of the builder are hidden from the director. As such, new representations can easily be integrated through the use of concrete building classes. The process of construction is controlled by the director explicitly. If changes need to be made, this can be done without consulting the client.

Cons of builder pattern

The builder pattern consists of a close coupling between the product, the specific builder, and the classes involved in the design process, so changes to the basic process can be difficult. The building (construction) of the objects often requires knowledge of their specific use and their environment. The use of known patterns, including the builder design pattern, can lead programmers to overlook simpler and more elegant solutions. Ultimately, many programmers consider the builder pattern as one of the less important design patterns.

When is the builder pattern used?

One way to illustrate the builder design pattern is to consider the example of a restaurant and a customer placing an order. Once the order has been received, the restaurant employees act to carry it out. The entire process up until the order delivery takes place ‘behind the scenes’. The guest doesn’t see what happens in the kitchen, for example, they’re ultimately being served the result (in programming language: print).

The following code examples further highlight the individual actors of the builder pattern.

The object, i.e. the menu, is empty to begin with. Content is added once an order is made:

public class Menu {
	private String starter = "No starter";
	private String maincourse = "No main course";
	private String dessert = "No dessert";
	private String drink = "No drink";
	public void setstarter (String starter) {
		this.starter = starter;
	}
	public void setmaincourse (String maincourse) {
		this.maincourse = maincourse;
	}
	public void setdessert(String dessert) {
		this.dessert = dessert;
	}
	public void setdrink(String drink) {
		this.drink = drink;
	}
	public void print() {
		System.out.println(
			"The food is ready! " + "\n" +
			" – Starter: " + starter +
			" – Main course: " + maincourse +
			" – Dessert: " + dessert +
			" – Drink: " + drink);
	}
}

The director provides the ‘environment’ so that a dish can be prepared – or built – for the guest. This environment is accessible to every guest. The guest only communicates with the director, so that the actual preparation remains hidden:

public class MattsRestaurant {
	private MenuBuilder menuBuilder;
	public void setBuilder(MenuBuilder menuBuilder) {
		this.menuBuilder = menuBuilder;
	}
	public Menu buildMenu(){
		menuBuilder.buildStarter();
		menuBuilder.buildMainCourse();
		menuBuilder.buildDessert();
		menuBuilder.buildDrink();
		return menuBuilder.build();
	}
}

Then the builder steps into action. In our example, this would be a chef:

public abstract class MenuBuilder {
	Menu menu = new Menu();
	abstract void buildStarter();
	abstract void buildMainCourse();
	abstract void buildDessert();
	abstract void buildDrink();
	Menu build()
{
		return menu;
	}
}

The specific builder, in this case the cook, builds (i.e. cooks) the individual components of the ordered dish. To do this, they override the ‘abstract’ menu items:

public class MenuOfTheDayBuilder extends MenuBuilder {
	@Override
	public void buildStarter() {
		burger.setStarter("Pumpkin soup");
	}
	@Override
	public void buildMainCourse() {
		burger.setMainCourse("Grilled steak with potatoes");
	}
	@Override
	public void buildDessert() {
		burger.setDessert("Vanilla ice cream");
	}
	@Override
	public void buildDrink() {
		burger.setDrink("Red wine");
	}
}

Lastly, the individual components of the dish are summarised and delivered to the guest, i.e. ‘printed out’.

public class Main {
	public static void main(String[] args) {
		MattsRestaurant mattsRestaurant = new MattsRestaurant();
		menuRestaurant.setBuilder(new MenuOfTheDayBuilderBuilder());
		buildMenu(menuRestaurant);
		menuRestaurant.setBuilder(new SpecialMenuBuilder());
		buildMenu(menuRestaurant);
	}
	private static void buildMenu(MattsRestaurant mattsRestaurant) {
		MenuOfTheDay menu = mattsRestaurant.buildMenu();
		menu.print();
	}
}
Note

This example is based on code written by Daniel Høyer Jacobsen, which is available on his website Design Patterns in Java.

Was this article helpful?
Page top