Builder Pattern in C#: Definition, Examples, Pros & Cons
The Builder pattern in C# separates the construction of a complex object from its representation so that the same construction process can create different representations.
The Builder pattern is a creational design pattern focused on constructing complex objects step by step. Instead of using a large constructor with many parameters, it provides a structured way to build an object incrementally. The pattern typically includes a builder interface, concrete builders, and optionally a director that orchestrates the construction process. It improves readability and flexibility, especially when objects have many optional or conditional properties. In modern C#, it is often implemented using a fluent interface for better developer experience.
Why We Use Builder Pattern in C#?
We use the Builder pattern to simplify the creation of complex objects and avoid constructors with too many parameters (the “telescoping constructor” problem). It improves code readability and allows different representations of an object to be created using the same process. It also helps enforce immutability by constructing objects step by step before finalizing them.
When to Use Builder Pattern in C#?
Use this pattern when creating objects with many optional or configurable properties. It is ideal when object construction involves multiple steps or validation rules. It is also useful when you need different representations of the same object or want to ensure immutability. If constructors become hard to manage or unclear, Builder is a good alternative.
Example Use Cases with C# Code
1. Fluent Builder for Complex Object (Product Configuration)
public class Computer
{
public string CPU { get; private set; }
public string RAM { get; private set; }
public string Storage { get; private set; }
public class Builder
{
private readonly Computer _computer = new Computer();
public Builder SetCPU(string cpu)
{
_computer.CPU = cpu;
return this;
}
public Builder SetRAM(string ram)
{
_computer.RAM = ram;
return this;
}
public Builder SetStorage(string storage)
{
_computer.Storage = storage;
return this;
}
public Computer Build()
{
return _computer;
}
}
}
Usage:
var computer = new Computer.Builder()
.SetCPU("Intel i7")
.SetRAM("16GB")
.SetStorage("1TB SSD")
.Build();
2. Step-by-Step Construction with Director
// Product
public class House
{
public string Walls { get; set; }
public string Roof { get; set; }
}
// Builder Interface
public interface IHouseBuilder
{
void BuildWalls();
void BuildRoof();
House GetHouse();
}
// Concrete Builder
public class ConcreteHouseBuilder : IHouseBuilder
{
private House _house = new House();
public void BuildWalls() => _house.Walls = "Concrete Walls";
public void BuildRoof() => _house.Roof = "Concrete Roof";
public House GetHouse() => _house;
}
// Director
public class HouseDirector
{
public House Construct(IHouseBuilder builder)
{
builder.BuildWalls();
builder.BuildRoof();
return builder.GetHouse();
}
}
3. Immutable Object Builder
public class Person
{
public string Name { get; }
public int Age { get; }
private Person(Builder builder)
{
Name = builder.Name;
Age = builder.Age;
}
public class Builder
{
public string Name { get; private set; }
public int Age { get; private set; }
public Builder SetName(string name)
{
Name = name;
return this;
}
public Builder SetAge(int age)
{
Age = age;
return this;
}
public Person Build()
{
return new Person(this);
}
}
}
Advantages of Builder Pattern in C#
• Improves readability with step-by-step construction
• Avoids constructors with many parameters
• Supports immutable object creation
• Provides flexible object creation process
• Enables reuse of construction logic
Disadvantages of Builder Pattern in C#
• Adds extra classes and complexity
• Overkill for simple objects
• Requires more boilerplate code
• Can increase maintenance if overused
Comparison with Similar Patterns
| Pattern | Purpose | Key Difference | Use Case |
|---|---|---|---|
| Builder | Construct complex objects step by step | Focuses on construction process | Objects with many optional fields |
| Abstract Factory | Create families of related objects | Creates multiple related objects at once | UI frameworks, product families |
| Factory Method | Create a single object | Uses inheritance for instantiation | Delegating object creation |
| Prototype | Clone existing objects | Uses copying instead of building | Performance-critical cloning |