Builder Pattern

Classic GOF Constructional Design Patterns

 
  

Intent

The Builder pattern builds a complex object using simple objects and using a step by step approach.

It is used when:

  • Separate the construction of a complex object from its representation so that the same construction process can create different representations.
  • Parse a complex representation, create one of several targets.
builder patterns
  

Problem

Supposing we have an object with many dependencies and need to acquire each one of these dependencies, certain actions have to be issued. In such cases, we can use the Builder pattern in order to:

  • Encapsulate, create, and assemble the parts of a complex object in a separate Builder object.
  • Delegate the object creation to a Builder object instead of creating the objects directly.
  

Discussion

The Builder pattern allows a client to construct a complex object by specifying the type and content only. Construction details are hidden from the client entirely. Specifically, the Builder pattern was introduced to solve some of the problems with Factory and Abstract Factory design patterns when the Object contains a lot of attributes.

There are some major issues with the Factory Method and Abstract Factory design patterns when the Object contains a lot of attributes:

  • Too Many arguments to pass from client program to the Factory class that can be error prone because most of the time, the type of arguments are the same and from client side its hard to maintain the order of the argument.
  • Some of the parameters might be optional but in the Factory pattern, we are forced to send all the parameters and optional parameters need to sent as NULL.
  • If the object is heavy and its creation is complex, then all that complexity will be part of Factory classes making it heavy and confusing.

We could solve the issues with large number of parameters by providing a constructor with required parameters and then different setter methods to set the optional parameters. The problem with this approach is that the Object state will be inconsistent until unless all the attributes are set explicitly. The Builder pattern solves the issue with large number of optional parameters and inconsistent state by providing a way to build the object step-by-step and provide a method that will actually return the final Object.

The most common motivation for using Builder is to simplify client code that creates complex objects. The client can still direct the steps taken by the Builder without knowing how the actual work is accomplished. Builders frequently encapsulate construction of Composite objects (another GoF design pattern) because the procedures involved are often repetitive and complex.

In many cases, it is the last step that returns the newly created object which makes it easy for a Builder to participate in fluent interfaces in which multiple method calls, separated by dot operators, are chained together (note: fluent interfaces are implementation of the Chaining Pattern as presented in the Implementation patterns section).

  

Structure

The Builder pattern allows us to write readable, understandable code to set up complex objects. It is often implemented with a fluent interface, which you may have seen in tools like Apache Camel or .NET. If you are familiar with fluent approaches to building objects, this should look very familiar.


builder structure

Let's examine the parts of the diagram above and explain what is going on.

  • Product – The product class defines the type of the complex object that is to be generated by the builder pattern.
  • Builder – This abstract base class defines all of the steps that must be taken in order to correctly create a product. Each step is generally abstract as the actual functionality of the builder is carried out in the concrete sub-classes. The GetResult method is used to return the final product. The builder class is often replaced with a simple interface.
  • ConcreteBuilder – There may be any number of concrete builder classes inheriting from Builder. These classes contain the functionality to create a particular complex product.
  • Director – The director class controls the algorithm that generates the final product object. A director object is instantiated and its Construct method is called. The method includes a parameter to capture the specific concrete builder object that is to be used to generate the product. The director then calls methods of the concrete builder in the correct order to generate the product object. On completion of the process, the GetResult method of the builder object can be used to return the product.
  

Practical Example

As stated earlier, the Builder pattern excels at creating objects that either have a large number of attributes or consist of a series of steps. There are many example processes that we could use as a practical example for these scenarios: building houses, selling a product, even making your evening dinner.

For our purposes, let's choose a business process that most engineers have done at some point in their career's: creating an email.


gof builder pattern for email

This looks very similar like the generic diagram in STRUCTURE above. Here we have an an abstract builder (IMessageBuilder) that acts as an interface for any number of concrete builders (EmailBuilder and TextBuilder in this case). The director (EmailService) simply instantiates an instance of the appropriate builder and uses it to create a message to be sent.

One of the things that should be noted is that the getPart() method may, and probably will, be replaced with a series of steps - each in their own method. You may notice here that each of these steps will return the EmailBuilder, allowing us to "chain" the methods together to complete the entire object build if desired. While this is common, it is not the only way to use the builder.

The createMsg() method is the final method that will be called on the builder to actually return the message object. In practice, this method will contain logic to ensure that the object (message in this case) is completely consistent and ready to be used.

  

Code Samples

Below, you will find examples of the Builder Pattern implemented in four different commonly used languages. Each one of the examples implements the exact same scenario as described in the PRACTICAL EXAMPLE section above.

Each sample will use a builder pattern to create and return an email object.


C# Builder Sample

In this C# example, we are implementing a simple builder that creates a message (either an email or a text message). We could easily extend this sample to include functionality to retrieve data dynamically to populate messages - but, we are keeping this simple to demonstrate the pattern.


Java Builder Sample

In this Java example, we are implementing a simple builder that creates a message. Unlike some of the other samples, this one will also show the ability to use the builder as a fluent interface and allow additional information to be passed in at various stages during the "building" process.

Also, in this example, we are focusing on only a single builder type - although this could be easily extended to support more.


Typescript Builder Sample

In this TypeScript example, we are implementing a simple builder that creates a message (either an email or a text message).


JavaScript Builder Sample

In this JavaScript example, we are implementing a simple builder that creates a message (either an email or a text message).


  

Considerations

  1. Decide if a common input and many possible representations (or outputs) is the problem at hand.
  2. Encapsulate the parsing of the common input in a Reader class.
  3. Design a standard protocol for creating all possible output representations. Capture the steps of this protocol in a Builder interface.
  4. Define a Builder derived class for each target representation.
  5. The client creates a Reader object and a Builder object, and registers the latter with the former.
  6. The client asks the Reader to "construct".
  7. The client asks the Builder to return the result.
  

Additional Notes

  • Sometimes creational patterns are complementary: Builder can use one of the other patterns to implement which components get built. Abstract Factory, Builder, and Prototype can use Singleton in their implementations.
  • Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the Abstract Factory is concerned, the product gets returned immediately.
  • Builder often builds a Composite.
  • Often, designs start out using Factory Method (less complicated, more customizable, sub-classes proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed.