C# Design Patterns: Fluent Builder Pattern

C# Design Patterns: Fluent Builder Pattern

Avoid adding multiple parameters to your method

ยท

3 min read

Suppose we have to build an object with a lot of different configurations based on a scenario. For example, we have to send an Email where we have optional properties like CC (carbon copy), BCC (blind carbon copy), attachments, etc. So the method to send an email would look somewhat like this:

public async Task<bool> SendEmailAsync(string subject, string htmlContent, string to, List<byte[]> attachments = null, List<string> cc = null, List<string> bcc = null)
{
    // code to send email
}

As we can see there are a lot of optional properties which we might not need always. So to tackle this, we can make use of one of the famous Gang of Four (GOF) design patterns i.e. Builder Pattern.

What is Builder Pattern?

As the name suggests, this design pattern is used to build complex objects in a step-by-step approach. Using the same construction process we can make different representations of the object.

Separate the construction of a complex object from its representation so that the same construction process can create different representations. - Design Patterns: Elements of Reusable Object-Oriented Software

So to solve the above problem, we will put Builder Pattern to use. We will have a EmailContent.cs class to define properties of the Email Object.

public class EmailContent
{
    public EmailContent()
    {
         To = new();
         Attachments = new();
         Cc = new();
         Bcc = new();
    }
    public string Subject { get; set; }
    public string HtmlContent { get; set; }
    public List<string> To { get; set; }
    public List<string> Cc { get; set; }
    public List<string> Bcc { get; set; }
    public List<byte[]> Attachments { get; set; }
}

Now we will add EmailContentBuilder.cs class to build EmailContent.cs

public class EmailContentBuilder
{
    private EmailContent _emailContent = new();
    // this method is called at the end which returns the final built object
    public EmailContent Build() => _emailContent;

    public EmailContentBuilder(string subject, string htmlContent, string to)
    {
         // initializing all the required fields in the constructor
         _emailContent.Subject = subject;
         _emailContent.HtmlContent = htmlContent;
         _emailContent.To = to;
     }

    public EmailContentBuilder WithAttachments(List<byte[]> attachments)
    {
        _emailContent.Attachments.AddRange(attachments);
        return this;
    }

    public EmailContentBuilder WithCarbonCopy(List<string> cc)
    {
        _emailContent.Cc.AddRange(cc);
        return this;
    }

   public EmailContentBuilder WithBlindCarbonCopy(List<string> bcc)
   {
        _emailContent.Bcc.AddRange(bcc);
        return this;
   }
}

Now we will use the above builder class to construct the EmailContent object.

// initialize email builder
EmailContentBuilder contentBuilder = new("Email using Builder Pattern",
    "<p> Html Content</p>",
    "test@example.com");
List<string> cc = new ();
List<byte[]> attachments = new();

// email having cc and attachments
EmailContent content = contentBuilder
   .WithCarbonCopy(cc)
   .WithAttachments(attachments)
   .Build();
await SendEmailAsync(content);

// email without cc and attachments
EmailContent content = contentBuilder.Build();
await SendEmailAsync(content);

And our SendEmailAsync() will look like:

public async Task<bool> SendEmailAsync(EmailContent content) 
{
    // code to send email
}

So there we have it, implementing Builder Design Pattern with a fluent approach.

coffee.png

Also, buy me a coffee, book or a pizza by clicking the image above if you like what I am doing and want to support me. ๐Ÿ˜…

Any other way we could put the Builder pattern to use? Let me know in the comments below. Till then, Happy Coding! ๐Ÿ‘จโ€๐Ÿ’ป

ย