Builder
Amir Doosti
.Net Software Engineer | 20+ Years of Expertise | C#, .NET, Microservices Architecture
The Builder Design Pattern is a creational pattern that separates the construction of complex objects from their representation, allowing the same construction process to create different representations. It enables the construction of objects step by step, facilitating the creation of complex objects with varying configurations. In this article, we'll examine the Builder pattern in depth, its implementation in C#, and provide an example to illustrate its usage.
1. Overview of the Builder Pattern
The Builder pattern is used to construct complex objects by breaking down the construction process into multiple steps. Suppose we have a class with lots of properties. So we need a huge constructor to assign value to all properties. If we don’t need to specify all properties we can pass null or we can overload lots of constructors. Both ways are not good. The best way is using the Builder Pattern. It defines an abstract builder interface that declares methods for building each part of the object, and concrete builder classes implement this interface to provide specific implementations of the construction process. A director class orchestrates the construction process, invoking methods on the builder to create the final object.
I created a solution in my GitHub that contains a project called Builder for this article. You can find it here:
2. Structure of the Builder Pattern
3. Implementation in C#
Let's demonstrate the Builder pattern with a simple example of building a computer:
// Product: Computer
public class Computer
{
public string CPU { get; set; }
public string RAM { get; set; }
public string GPU { get; set; }
public string Storage { get; set; }
}
// Builder Interface
public interface IComputerBuilder
{
void SetCPU(string cpu);
void SetRAM(string ram);
void SetGPU(string gpu);
void SetStorage(string storage);
Computer Build();
}
// Concrete Builder: ComputerBuilder
public class ComputerBuilder : IComputerBuilder
{
private Computer computer = new Computer();
public void SetCPU(string cpu) { computer.CPU = cpu; }
public void SetRAM(string ram) { computer.RAM = ram; }
public void SetGPU(string gpu) { computer.GPU = gpu; }
public void SetStorage(string storage) { computer.Storage = storage; }
public Computer Build() { return computer; }
}
// Director
public class GamingDirector
{
private IComputerBuilder builder;
public GamingDirector(IComputerBuilder builder)
{
this.builder = builder;
}
public Computer Construct()
{
builder.SetCPU("Intel Core i7");
builder.SetRAM("16GB DDR4");
builder.SetGPU("NVIDIA GeForce RTX 3080");
builder.SetStorage("1TB SSD");
return builder.Build();
}
}
In this example Computer is the main product that we want to build but it has lots of parameters so we are using a builder pattern.?
IComputerBuilder is defining an interface for our pattern and ComputerBuilder is the concrete builder class that can create a “Computer” object.?
Note that the builder may pass or set some default parameters of the product (Computer). Also we may design the setting functions so that we can chain the settings like this:
builder.SetCPU("Intel Core i7").SetRAM("16GB DDR4");
And finally note that it is possible to combine builder and product in one class. In this case a product can create an object of its type but in a step by step manner.
4. Usage of the Builder Pattern
class Program
{
static void Main(string[] args)
{
// Create a director
GamingDirector director = new GamingDirector(new ComputerBuilder());
// Construct a gaming computer
Computer gamingComputer = director.Construct();
}
}
5. Benefits of the Builder Pattern
6. When to Use the Builder Pattern
Existing Builder in .NET
While there are not many explicit examples of the Builder pattern in the .NET framework itself, there are several instances where the pattern is implicitly used or where libraries and frameworks employ the concept of builders for object creation and configuration. Here are five examples along with explanations of why they can be considered instances of the Builder pattern:
1. Entity Frameworks DbContextOptionsBuilder
2. ASP.NET Cores IServiceCollection
3. HttpClientBuilder in ASP.NET Cores AddHttpClient extension method
4. FluentAssertions AssertionOptions
5. Moqs MockRepository
Conclusion
In conclusion, the Builder Design Pattern provides a structured and flexible approach to construct complex objects step by step. By following the principles outlined in this article and using the provided example, you can leverage the Builder pattern in your C# applications to create complex objects with varying configurations in a clear and maintainable manner.
#designpattern #builder #csharp #dotnet