The Builder design pattern is a creational design pattern that lets us create an object one step at a time. It is quite common to use this pattern when creating a complex object. By using this pattern, we can create different parts of an object, step by step, and then connect all the parts together.

Without this pattern, we can end up with a large constructor to provide all the required parameters for constructing our object. That could lead to quite unreadable and hardly maintainable code. Furthermore, a constructor with lots of parameters has a downside to it. We won’t need to use all the parameters, all the time.

In this article, we are going to show you how to implement the Builder pattern to avoid such complex constructors. We will go even further and explain the Builder Recursive Generics design pattern and Faceted Builder design pattern as well in our next articles.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

You can download the source code from here: Builder Design Pattern – Source Code

For the main page of this series check out C# Design Patterns.

Implementing the Builder Design Pattern

We are going to write a simple example of creating a stock report for all the products in our store.

So, let us start with a simplified Product class:

public class Product
{
    public string Name { get; set; }
    public double Price { get; set; }
}

We are going to use this class just for storing some basic data about a single product.

Our stock report object is going to consist of the header, body and footer parts. So, it is quite logical to divide the object building process into those three actions. First, let’s start with the ProductStockReport class:

public class ProductStockReport
{
    public string HeaderPart { get; set; }
    public string BodyPart { get; set; }
    public string FooterPart { get; set; }

    public override string ToString() =>
        new StringBuilder()
        .AppendLine(HeaderPart)
        .AppendLine(BodyPart)
        .AppendLine(FooterPart)
        .ToString();
}

This is the object, we are going to build with the Builder design pattern.

To continue on, we need a builder interface to organize the building process:

public interface IProductStockReportBuilder
{
    void BuildHeader();
    void BuildBody();
    void BuildFooter();
    ProductStockReport GetReport();
}

We can see that the concrete builder class which is going to implement this interface, needs to create all the parts for our stock report object and return that object as well. So, let’s implement our concrete builder class:

public class ProductStockReportBuilder : IProductStockReportBuilder
{
    private ProductStockReport _productStockReport;
    private IEnumerable<Product> _products;

    public ProductStockReportBuilder(IEnumerable<Product> products)
    {
        _products = products;
        _productStockReport = new ProductStockReport();
    }

    public void BuildHeader()
    {
        _productStockReport.HeaderPart = $"STOCK REPORT FOR ALL THE PRODUCTS ON DATE: {DateTime.Now}\n";
    }

    public void BuildBody()
    {
        _productStockReport.BodyPart = string.Join(Environment.NewLine, _products.Select(p => $"Product name: {p.Name}, product price: {p.Price}"));
    }

    public void BuildFooter()
    {
        _productStockReport.FooterPart = "\nReport provided by the IT_PRODUCTS company.";
    }

    public ProductStockReport GetReport()
    {
        var productStockReport = _productStockReport;
        Clear();
        return productStockReport;
    }

    private void Clear() => _productStockReport = new ProductStockReport();
}

This logic is quite straight forward. We receive all the products required for our report and instantiate the _productStockReport object. Then, we create all the parts of our object and finally return it. In the GetReport method, we reset our object and prepare a new instance to be ready to create another report. This is usual behavior but it is not mandatory.

Once our building logic is over, we can start building our object in a client class or even encapsulate the building process from the client class inside a Director class. Well, this is exactly what we are going to do:

public class ProductStockReportDirector
{
    private readonly IProductStockReportBuilder _productStockReportBuilder;

    public ProductStockReportDirector(IProductStockReportBuilder productStockReportBuilder)
    {
        _productStockReportBuilder = productStockReportBuilder;
    }

    public void BuildStockReport()
    {
        _productStockReportBuilder.BuildHeader();
        _productStockReportBuilder.BuildBody();
        _productStockReportBuilder.BuildFooter();
    }
}

Creating  the StockReport Object

After we have finished all this work, we can start building our object:

class Program
{
    static void Main(string[] args)
    {
        var products = new List<Product>
        {
            new Product { Name = "Monitor", Price = 200.50 },
            new Product { Name = "Mouse", Price = 20.41 },
            new Product { Name = "Keyboard", Price = 30.15}
        };

        var builder = new ProductStockReportBuilder(products);
        var director = new ProductStockReportDirector(builder);
        director.BuildStockReport();

        var report = builder.GetReport();
        Console.WriteLine(report);
    }
}

The result :

Builder Design Pattern - Result

Excellent. We have created our object with the Builder design pattern.

Fluent Builder

The Fluent builder is a small variation of the Builder design pattern, which allows us to chain our builder calls towards different actions. To implement the Fluent builder, we are going to change the builder interface first:

public interface IProductStockReportBuilder
{
    IProductStockReportBuilder BuildHeader();
    IProductStockReportBuilder BuildBody();
    IProductStockReportBuilder BuildFooter();
    ProductStockReport GetReport();
}

We have to modify the implementation of the ProductStockReportBuilder class as well:

public IProductStockReportBuilder BuildHeader()
{
    _productStockReport.HeaderPart = $"STOCK REPORT FOR ALL THE PRODUCTS ON DATE: {DateTime.Now}\n";
    return this;
}

public IProductStockReportBuilder BuildBody()
{
    _productStockReport.BodyPart = string.Join(Environment.NewLine, _products.Select(p => $"Product name: {p.Name}, product price: {p.Price}"));
    return this;
}

public IProductStockReportBuilder BuildFooter()
{
    _productStockReport.FooterPart = "\nReport provided by the IT_PRODUCTS company.";
    return this;
}

As a result of these modifications, we can chain the calls in the Director class:

public void BuildStockReport()
{
    _productStockReportBuilder
        .BuildHeader()
        .BuildBody()
        .BuildFooter();
}

If we start our application now, the result is going to be the same, but this time we use the fluent interface.

Conclusion

In this article, we have learned about how to create Builder Design Pattern and how to implement it into our project to create complex objects. Furthermore, we have expanded our example to use the Fluent interface, which allows us to chain our Builder calls together.

In the next article, we are going to learn how to implement Fluent Builder Interface With Recursive Generics.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!