Fluent Builder
Tags: programming, designpatterns, softwareenginee, softwaredevelopment
Published: 2022-11-22 10:55:14

Another way to implement the [builder pattern](https://thkarropoulos.hashnode.dev/builder-pattern) is with fluent builder. Fluent builder provides a more readable and straightforward way to create objects. The pattern is implemented by having a series of methods that return the builder type itself and a build method that returns an instance of the class we are building.<br/>For our example we are going to create a Desktop PC builder.<br/>
Bellow is the sample code:

```csharp
public interface IDesktopBuilder
{
    IDesktopBuilder WithCase(string @case);
    IDesktopBuilder WithCpu(string cpu);
    IDesktopBuilder WithMotherBoard(string motherboard);
    IDesktopBuilder WithVideoCard(string videoCard);
    IDesktopBuilder WithOperatingSystem(string operatingSystem);
    Desktop Build();
}
```

```csharp
public class DesktopBuilder : IDesktopBuilder
{
    private readonly Desktop _desktop;
    
    public DesktopBuilder()
    {
        _desktop = new Desktop();
    }
    
    public IDesktopBuilder WithCase(string @case)
    {
        _desktop.Case = @case;
        return this;
    }

    public IDesktopBuilder WithCpu(string cpu)
    {
        _desktop.Cpu = cpu;
        return this;
    }

    public IDesktopBuilder WithMotherBoard(string motherboard)
    {
        _desktop.Motherboard = motherboard;
        return this;
    }

    public IDesktopBuilder WithVideoCard(string videoCard)
    {
        _desktop.VideoCard = videoCard;
        return this;
    }

    public IDesktopBuilder WithOperatingSystem(string operatingSystem)
    {
        _desktop.OperatingSystem = operatingSystem;
        return this;
    }

    public Desktop Build()
    {
        return _desktop;
    }
}
```

```csharp
public class DesktopPc
{
    public string Case { get; set; }
    public string Motherboard { get; set; }
    public string Cpu { get; set; }
    public string VideoCard { get; set; }
    public string OperatingSystem { get; set; }
}
``` 
Finally we can create a Desktop PC by using the fluent builder by the following way

```csharp
DesktopPc desktop = new DesktopBuilder()
    .WithCase("Mini Tower Case")
    .WithCpu("3.6Ghz 12 cores")
    .WithMotherBoard("Gaming board")
    .WithVideoCard("Gaming v3 12GB")
    .WithOperatingSystem("64bit OS")
    .Build();
``` 
Or if we do not want to add an Operating System in our Desktop setup

```csharp
DesktopPc desktop = new DesktopBuilder()
    .WithCase("Mini Tower Case")
    .WithCpu("3.6Ghz 12 cores")
    .WithMotherBoard("Gaming board")
    .WithVideoCard("Gaming v3 12GB")
    .Build();
``` 
### Progressive Builder (progressive interface)
Although the fluent builder pattern gives us a more readable way to create an object, there is a drawback with the above approach. We can't tie the way we construct the object, for example if there is a need to select motherboard before adding a CPU. Also even though we have already used a method, this method remains available and we can use it again as shown in the image bellow. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pfija0qix69ltxob9iuz.png)
 
To achieve such a behavior we can utilize the Progressive Builder pattern. With progressive interface we can use multiple builder patterns in a sequential way. This allow us to chain in a fixed sequence the method calls. The advantage of this implementation is that we  ensure that the object is built in the correct order.<br/>
For example we want to build a desktop pc but in the following order.
- Select a case
- Select a motherboard
- Select a CPU
- Select a video card
- Select operating system

For this to be done we will create separate interface for each desktop property and everyone of them is going to have a returning type the interface that comes next in the chain.<br/>

Bellow is the sample code:

```csharp
public interface IProgressiveBuilder
{
    ICaseBuilder WithCase(string @case);
}

public interface ICaseBuilder
{
    IMotherboardBuilder WithMotherboard(string motherboard);
}

public interface IMotherboardBuilder
{
    ICpuBuilder WithCpu(string cpu);
}

public interface ICpuBuilder
{
    IVideoCardBuilder WithVideoCard(string videoCard);
}

public interface IVideoCardBuilder
{
    IOperatingSystemBuilder WithOperatingSystem(string operatingSystem);
}

public interface IOperatingSystemBuilder
{
    ProgressiveDesktop Create();
}
``` 

```csharp
public class ProgressiveDesktop :
    IProgressiveBuilder,
    ICaseBuilder,
    IMotherboardBuilder,
    ICpuBuilder,
    IVideoCardBuilder,
    IOperatingSystemBuilder
{
    public string Case;
    public string Motherboard;
    public string Cpu;
    public string VideoCard;
    public string OperatingSystem;
    
    // Keep constructor private to avoid 
    // instantiation of the class outside of the builder
    private ProgressiveDesktop()
    {
        
    }

    public static IProgressiveBuilder Build()
    {
        return new ProgressiveDesktop();
    }

    public ICaseBuilder WithCase(string @case)
    {
        Case = @case;
        return this;
    }

    public IMotherboardBuilder WithMotherboard(string motherboard)
    {
        Motherboard = motherboard;
        return this;
    }

    public ICpuBuilder WithCpu(string cpu)
    {
        Cpu = cpu;
        return this;
    }

    public IVideoCardBuilder WithVideoCard(string videoCard)
    {
        VideoCard = videoCard;
        return this;
    }

    public IOperatingSystemBuilder WithOperatingSystem(string operatingSystem)
    {
        OperatingSystem = operatingSystem;
        return this;
    }

    public ProgressiveDesktop Create()
    {
        return this;
    }
}
``` 

```csharp
// Build desktop object with the use of progressive builder
ProgressiveDesktop desktop =  ProgressiveDesktop
            .Build()
            .WithCase("Mini Tower Case")
            .WithMotherboard("Gaming board")
            .WithCpu("3.6Ghz 12 cores")
            .WithVideoCard("Gaming v3 12GB")
            .WithOperatingSystem("64bit OS")
            .Create();
``` 
Now when creating a progressive desktop the only available method is the `Build`.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6ecg7j2qv3pfwxn047y.png)

Respectively the only available method after `Build` is the `WithCase` since this is the next  in chain method.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h00102dn4cop9550tng0.png)