DEV Community

Cover image for Builder design pattern for objects with nested properties
Ali Alp
Ali Alp

Posted on • Updated on

 

Builder design pattern for objects with nested properties

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; }
}
Enter fullscreen mode Exit fullscreen mode

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}";
    }
}
Enter fullscreen mode Exit fullscreen mode

so it can be used like this

var result = new DataBuilder()
            .Id("11")
            .Datetime(DateTime.Now)
            .Build();
Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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}";
    }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Happy coding :)

Top comments (2)

Collapse
 
rajajaganathan profile image
Raja Jaganathan • Edited

Mostly I use build pattern to construct payload for third party or api. By the way it's really usefully!

Collapse
 
chrisribe profile image
ChrisRibe

Thanks for the article, very useful :)
Here is a reimplementation in Javascript / Typescript.

codesandbox.io/s/builder-pattern-n...

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.