Builder

Intent

Builder is a creational design pattern that lets you produce different types and representations of an object using the same building process. Builder allows constructing complex objects step by step.

Problem

Imagine a complex object that requires laborious step by step initialization of many fields and nested objects. Such code is usually buried inside a constructor with lots of parameters, or worse, scattered all over the client code.

For example, let's think how to create a House object. To build a simple house, you need to construct four walls, install a door and two windows, build a roof. But what if you want a bigger, brighter house, with a backyard and other goodies?

The simplest solution that comes to mind is to extend the base House class and to create subclasses to cover all combinations of the parameters. The obvious problem with this approach is a considerable number of subclasses you will end up with. Any new parameter, such as porch style, will require growing this hierarchy even more.

On the other hand, you can create a giant constructor in the base House class that accepts all possible parameters of resulting house. While this approach will indeed eliminate the need for sublcasses, it will also create another problem.

Some of these parameters will be unused most of the time, making constructors calls pretty ugly. For instance, most houses do not have a swimming pool. Therefore, all parameters related to swimming pools will be useless in 99% of cases.

Solution

The Builder pattern suggests to extract the object construction code out of its own class and move it to separate objects called builders.

The pattern organizes the object construction into a set of steps (such as buildWalls, buildDoor, etc.) To create an object, you will need to call several building steps in a builder class. The important part here is that you do not need to call all the steps. You can use only the steps necessary for producing a particular configuration of an object.

Often, the same construction step will be different for various products that you are trying to build. For example, a cabin may be build with wooden logs, but a castle must be build with stone.

In this case, you can create several different builder classes that implement the same building steps in a different manner. Then you can use these builders in the same construction process to produce different kinds of objects.

For example, there is a StoneBuilder class that makes everything from stone and a WoodBuilder class that uses wood. You could pass one of them through a set of construction steps to produce a house built either from stone or wood. This would work only if the client code that calls building steps interacts with builders using their common interface.

You can go even further and extract the whole construction process to a special class called Director. In this case, the Director will be defining the order of building steps, and a Builder object, linked with the Director, will execute them. This structure will hide any construction details from client code.

Structure

Builder design pattern
  1. Builder declares steps required to build a product.

  2. Concrete Builders provide different implementations of the construction steps. Builders can also provide methods for fetching a construction result. This method can not be declared inside the builder interface, because builders may produce products that do not have the common interface. But if you are dealing with products from a single hierarchy, then this method can be safely described in the base interface.

  3. Product is an object created as a result of construction. Builders can produce products that do not belong to the same class hierarchy or interface. It is a key difference between the Builder and other creational patterns.

  4. Director constructs products using a Builder object. Usually, client assigns a builder instance to a director just once via constructor parameters. Then director uses that single builder object for all further construction. But there is an alternative when a builder is passed to the main production method of a director.

  5. Note, that Builder does not require creating a director class. The separate director class is handy when you have several product variations that require different construction processes. Director can encapsulate all that code inside a single class.

Pseudocode

This example illustrates how Builder is used for the step-by-step construction of cars. The director class produces various models of cars using a different set of construction steps. Director works with a build object that was given to him. This allows you to reuse existing construction code for producing user manuals for various car models. To achieve this, you just need to a new builder class.

Therefore, the Builder design pattern allows you to create different variations of products, simply by changing the amount and order of the construction steps. Also, you can produce an entirely different type of product using the same construction code, by submitting an alternative version of a builder object.

// Builder can create different products using the same building process.
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 Manual is
    Textual representation of a car.


// Builder interface defines all possible ways to configure a product.
interface Builder is
    method reset()
    method setSeats(number)
    method setEngine(engine: Engine)
    method setTripComputer()
    method setGPS()

// Concrete builders implement that interface differently.
class CarBuilder implements Builder is
    private field car:Car
    method reset()
        Put a new Car instance into the "car" field.
    method setSeats(number) is
        Set the number of seats in car.
    method setEngine(engine: Engine) is
        Install a given engine.
    method setTripComputer() is
        Install a trip computer.
    method setGPS() is
        Install a global positioning system.
    method getResult(): Car is
        Return the current car object.

// Unlike other creational patterns, Builder can construct unrelated products,
// which don't have the common interface.
class CarManualBuilder implements Builder is
    private field manual:Manual
    method reset()
        Put a new Manual instance into the "manual" field.
    method setSeats(number) is
        Document car seats features.
    method setEngine(engine: Engine) is
        Add an engine instruction.
    method setTripComputer() is
        Add a trip computer instruction.
    method setGPS() is
        Add GPS instruction.
    method getResult(): Manual is
        Return the current manual object.


// Director defines the order of building steps. It works with a builder object
// through common Builder interface. Therefore it may not know what product is
// being built.
class Director is
    method constructSportsCar(builder: Builder) is
        builder.reset();
        builder.setSeats(2);
        builder.setEngine(new SportEngine());
        builder.setTripComputer();
        builder.setGPS();


// Director gets the concrete builder object from the client (application code).
// That's because application knows better which builder to use to get a
// specific product.
class Application is
    method makeCar is
        director = new Director();

        CarBuilder builder = new CarBuilder();
        director.constructSportsCar(builder);
        Car car = builder.getResult();

        CarManualBuilder builder = new CarManualBuilder();
        director.constructSportsCar(builder);

        // The final product is often retrieved from a builder object, since
        // Director is not aware and not dependent on concrete builders
        // and products.
        Manual manual = builder.getResult();

Applicability

When you have a "telescopic" constructor.

A constructor with a dozen of optional parameters is not convenient to call. You have to specify all of the parameters, even if you do not need them.

To ease the pain, one can overload a long constructor and create several shorter versions with fewer parameters. They will still call the main constructor, but pass some default values into omitted parameters.

The Builder pattern allows building objects step by step. Moreover, you can use only required steps and skip the optional ones when building a simple object.

When your code has to create different representations of one product (for example, stone and wooden houses). Construction of the product has similar steps that differ in details. Plus, although the products may be similar, they do not necessary have to have a common base class or interface.

Builder can be used to construct different products using the same building process.

Each distinct product will be represented by a separate builder class. Code that controls the construction order may live in a single director class.

When you have to build a Composite tree or another complex object.

Builder constructs products steps by step. It allows deferred or even recursive building that is mandatory when you are working with tree structures. Builder does not expose unfinished product while running construction steps. This prevents client code from getting corrupted results.

How to Implement

  1. Make sure that you have the common steps of building the product, as well as variations of the steps that lead to the creation of various representations of products.

  2. Create the Builder interface and declare production steps in it.

  3. Create a Concrete Builder class for each of the product representations. Implement their construction steps.

  4. Think about creating a Director class. Its methods should create different product configurations, using different steps of the same builder instance.

  5. The client code creates both Builder and Director objects. It creates a builder instance first and then passes it either to the director's constructor or its production methods.

  6. The client should call a production method of a Director object to begin the construction process.

  7. The result can be obtained from the Director object only if all products have a common interface. In the opposite case, each Builder must have its own method of retrieving the result.

Pros and Cons

  • Allows building products step by step.
  • Allows using the same code for building different products.
  • Isolates the complex construction code from a product's core business logic.
  • Increases overall code complexity by creating multiple additional classes.

Relations with Other Patterns

  • Often, designs start out using Factory Method (less complicated, more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complex) as the designer discovers where more flexibility is needed.

  • Builder focuses on constructing a complex object step by step. Abstract Factory creates families of product objects (either simple or complex). Builder returns the product as a final step, but the Abstract Factory returns the result immediately.

  • Builder can be used to build a complex Composite tree step by step.

  • Builder can be structured as a Bridge pattern: Director will act as interface, and Builders will play the role of implementations.

  • Abstract Factory, Builder and Prototype can be implemented as Singletons.

Implementations in Different Programming Languages

Java