In the previous blog, we explored the Fluent Builder Design Pattern, including:
- Product
- Builder interface that declares fluent behaviour
- Concrete Builder in which each SET returns the builder itself
- Chaining of the calls of SETs from client code
We learned how the Fluent Builder Pattern helps solve the traditional builder design pattern issue of many lines of code and hard mantainablity.
Before continuing this blog, I recomment to read the previous blog by clicking here
Immutable Builder Pattern
One major improvement to the traditional Builder Pattern is immutability.
An immutable object is an object whose state cannot change after it is created.
This makes programs safer because:
- No accidental modifications
- Better thread safety
- More predictable behavior
Immutable Product
Instead of allowing properties to be modified, we make them read-only. So let’s modify the User Class
public class User
{
public string Name { get; } //readonly
public string Email { get; } //readonly
public string Phone { get; } //readonly
public string Address { get; } //readonly
public int Age { get; } //readonly
public User(string name, string email, string phone, string address, int age)
{
Name = name; // set once
Email = email; // set once
Phone = phone; // set once
Address = address; // set once
Age = age; // set once
}
}
Notice there are no setters.
Values will be assigned once object is created.
Once the object is created, its values cannot change.
Immutable Builder
The builder collects values temporarily and creates the immutable object only when Build() is called.
public class ImmutableUserBuilder
{
private string _name; // collector
private string _email; // collector
private string _phone; // collector
private string _address; // collector
private int _age; // collector
public ImmutableUserBuilder SetName(string name)
{
_name = name; // sets once
return this;
}
public ImmutableUserBuilder SetEmail(string email)
{
_email = email; // sets once
return this;
}
public ImmutableUserBuilder SetPhone(string phone)
{
_phone = phone; // sets once
return this;
}
public ImmutableUserBuilder SetAddress(string address)
{
_address = address; // sets once
return this;
}
public ImmutableUserBuilder SetAge(int age)
{
_age = age; // sets once
return this;
}
public User Build()
{
// passes collected values to the constructor and make them read only
return new User(_name, _email, _phone, _address, _age);
}
}
Usage:
var user = new ImmutableUserBuilder()
.SetName("Avinash")
.SetEmail("xyz@abc.com")
.SetAge(30)
.Build()
Now the created User object cannot be modified.
When to Use an Immutable Builder
Use an Immutable Builder when the final object must be immutable (cannot change after creation).
- When the object must be thread-safe – Immutable objects are naturally thread-safe because their state never changes. Like Configuration objects, System settings, DTOs shared across threads etc.
- When you want to prevent accidental modification – In large systems objects often travel across layers. If they are mutable, someone might change them unintentionally.
- When the object represents a fixed state – When the object represents a fixed state
- When you want functional-style design – Immutable builders fit well with – Functional programming, Event-driven architecture, Domain-driven design
When NOT to Use an Immutable Builder
- When the object changes frequently
- When performance is critical and objects are created very frequently
- The object needs frequent state changes.
That’s it for the blog, In the next blog we will study about Step Builder Pattern. To read the blog click here
Thanks for reading










