A typical builder design pattern is suitable for a one-dimensional domain object like this
public class Data
{
public string Id { get; set; }
public DateTime DateTime { get; set; }
}
and its corresponding builder class will be as follows
public class DataBuilder
{
private readonly Data _data;
public DataBuilder()
{
_data = new Data();
}
public DataBuilder Id(string id)
{
this._data.Id = id;
return this;
}
public DataBuilder Datetime(DateTime dateTime)
{
this._data.DateTime = dateTime;
return this;
}
public string Build()
{
return $"id: {_data.Id} date:{_data.DateTime}";
}
}
so it can be used like this
var result = new DataBuilder()
.Id("11")
.Datetime(DateTime.Now)
.Build();
but what if our domain object consist of other domain objects like this
public class Data
{
public string Id { get; set; }
public DateTime DateTime { get; set; }
public Nested Nested { get; set; }
}
public class Nested
{
public string Name { get; set; }
public string Surname { get; set; }
}
in this case the beauty of the usage of the builder pattern will be somehow compromised
var nested = new Nested()
{
Name="Ali",
Surname="Tabryzy"
};
var result = new DataBuilder()
.Id("11")
.Nested(nested)
.Datetime(DateTime.Now)
.Build();
In order to keep the beauty of the builder pattern we can implement it like this
public class DataBuilder
{
private readonly Data _data;
public readonly NestedBuilder Nested;
private Nested _nested;
public class NestedBuilder
{
private readonly DataBuilder _dataBuilder;
public NestedBuilder(DataBuilder dataBuilder)
{
_dataBuilder = dataBuilder;
}
public DataBuilder Name(string name)
{
if (_dataBuilder._nested == null)
_dataBuilder._nested = new Nested();
_dataBuilder._nested.Name = name;
return _dataBuilder;
}
public DataBuilder Surname(string surname)
{
if (_dataBuilder._nested == null)
_dataBuilder._nested = new Nested();
_dataBuilder._nested.Surname = surname;
return _dataBuilder;
}
}
public DataBuilder()
{
_data = new Data();
Nested = new NestedBuilder(this);
}
public DataBuilder Datetime(DateTime dateTime)
{
this._data.DateTime = dateTime;
return this;
}
public DataBuilder Id(string id)
{
this._data.Id = id;
return this;
}
public string Build()
{
return $"id: {_data.Id} name:" +
$"{_nested.Name} surname: {_nested.Surname} date:{_data.DateTime}";
}
}
which the usage will be as beautiful as it is for a one-dimensional domain object as follows
var result = new DataBuilder()
.Id("11")
.Nested.Name("ali")
.Nested.Surname("Tabryzy")
.Datetime(DateTime.Now)
.Build();
Happy coding :)
Top comments (2)
Mostly I use build pattern to construct payload for third party or api. By the way it's really usefully!
Thanks for the article, very useful :)
Here is a reimplementation in Javascript / Typescript.
codesandbox.io/s/builder-pattern-n...