DEV Community

Jimmy
Jimmy

Posted on • Updated on

Nested builders with Action<T>

Once I started to use the Builder Pattern it didn't take long until I faced more complex objects on multi levels.

My first solution to this was to add a method returning a new Builder and in that builder have a Complete method that would return my original Builder.

Sounds complex doesn't it? It sure is! Once I got beyond 2 levels of nesting the builder implementation was a real hell every time.

Then I discovered I could use Action, where T is another Builder. This made my builders easier to implement, and also easier to maintain.

Here's a code example on how it could look like:

public class Person
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public List<Person> Children { get; set }
}

public class PersonBuilder 
{
    private readonly Person _person;

    public PersonBuilder()
    {
        _person = new Person();
    }

    public PersonBuilder Firstname(string firstname)
    {
        _person.Firstname = firstname;

        return this;
    }

    public PersonBuilder Lastname(string lastname)
    {
        _person.Lastname = lastname;

        return this;
    }

    public PersonBuilder AddChild(Action<PersonBuilder> builder)
    {
        var personBuilder = new PersonBuilder();
        builder(personBuilder);

        _person.Children.Add(personBuilder.Build())

        return this;
    }

    public Person Build()
    {
        return _person;
    }
}

var person = new PersonBuilder()
                        .Firstname("John")
                        .Lastname("Doe")
                        .AddChild(child => {
                               child.Firstname("Jane")
                                    .Lastname("Doe")
                        })
                        .Build();

Top comments (2)

Collapse
 
paulvanbladel profile image
paul van bladel • Edited

When you invoke the action delegate, it's more readable/understandable to also call the Invoke method of the action delegate.
Sorry... just a detail.

public PersonBuilder AddChild(Action<PersonBuilder> builder)
        {
            var personBuilder = new PersonBuilder();
            builder.Invoke(personBuilder); // instead of builder(personBuilder)

            _person.Children.Add(personBuilder.Build());

            return this;
        }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
paulvanbladel profile image
paul van bladel • Edited

Very Elegant, thanks for sharing.
Small bug, you need to initialize the Children List:

    public class Person
    {
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public List<Person> Children { get; set; } 
                 = new();
    }
Enter fullscreen mode Exit fullscreen mode