In the previous two articles, we were talking about Builder Design Pattern and Fluent Builder With Recursive Generics. We recommend reading at least the first one for a better understanding of the Builder Design Pattern. The second one is the upgrade to the first article and if you want to learn more about using recursive generics with the Builder Pattern, then we recommend reading that one as well.

Why do we need the Faceted Builder?

Sometimes we may have a complex object, and the creational process requires more than one builder class. So, what we need to do is to introduce multiple builder classes in such a way, that we can jump from one builder to another while creating our object.

Faceted Builder approach helps us a lot in that process because we create a facade over our builders and it allows us to use all the builders to create a single object.

Let’s learn how to do that.

The source code is available at Faceted Builder – Source Code.

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

This article is divided into the following sections:

Faceted Builder Implementation

We are going to start with a “complex” object model:

public class Car
{
    public string Type { get; set; }
    public string Color { get; set; }
    public int NumberOfDoors { get; set; }

    public string City { get; set; }
    public string Address { get; set; }

    public override string ToString()
    {
        return $"CarType: {Type}, Color: {Color}, Number of doors: {NumberOfDoors}, Manufactured in {City}, at address: {Address}";
    }
} 

We have the info part and the address part of our object, so we are going to use two builders to create this whole object.

As we said, we need a facade, so, let’s start with that:

public class CarBuilderFacade
{
    protected Car Car { get; set; }

    public CarBuilderFacade()
    {
        Car = new Car();
    }

    public Car Build() => Car;
}

We instantiate the Car object, which we want to build and expose it through the Build method.

What we need now is to create concrete builders. So, let’s start with the CarInfoBuilder which needs to inherit from the facade class:

public class CarInfoBuilder: CarBuilderFacade
{
    public CarInfoBuilder(Car car)
    {
        Car = car;
    }

    public CarInfoBuilder WithType(string type)
    {
        Car.Type = type;
        return this;
    }

    public CarInfoBuilder WithColor(string color)
    {
        Car.Color = color;
        return this;
    }

    public CarInfoBuilder WithNumberOfDoors(int number)
    {
        Car.NumberOfDoors = number;
        return this;
    }
}

As we can see, we receive, through the constructor, an object we want to build and use the fluent interface for building purpose.

Let’s do the same for the CarAddresBuilder class:

public class CarAddressBuilder: CarBuilderFacade
{
    public CarAddressBuilder(Car car)
    {
        Car = car;
    }

    public CarAddressBuilder InCity(string city)
    {
        Car.City = city;
        return this;
    }

    public CarAddressBuilder AtAddress(string address)
    {
        Car.Address = address;
        return this;
    }
}

At this moment we have both builder classes, but we can’t start building our object yet because we haven’t exposed our builders inside the facade class. Well, let’s do that:
public class CarBuilderFacade
{
    protected Car Car { get; set; }

    public CarBuilderFacade()
    {
        Car = new Car();
    }

    public Car Build() => Car;

    public CarInfoBuilder Info => new CarInfoBuilder(Car);
    public CarAddressBuilder Built => new CarAddressBuilder(Car);
}

As of this moment, we can start building our object:
class Program
{
    static void Main(string[] args)
    {
        var car = new CarBuilderFacade()
            .Info
              .WithType("BMW")
              .WithColor("Black")
              .WithNumberOfDoors(5)
            .Built
              .InCity("Leipzig ")
              .AtAddress("Some address 254")
            .Build();

        Console.WriteLine(car);
    }
}

And that is it. We have built our object with the Faceted Builder approach.

Conclusion

With this article, we are finished with the small Builder Design Pattern series, but we have more articles to come about Design Patterns in C#. So stay tuned.